Functions add/diff/cmp for xtime

Paul Eggert eggert at twinsun.com
Wed Oct 7 09:50:06 UTC 1998


   Date: Tue, 06 Oct 1998 16:43:08 +0100
   From: Markus Kuhn <Markus.Kuhn at cl.cam.ac.uk>

   I suggest to add the following three functions.

xtime_diff and xtime_add do not always report the correct answer; they
suffer from rounding errors.  This is inherent to the interface, at
least on the vast majority of hosts (e.g. hosts where `double' is IEEE
double-precision).  Applications that want to work reliably on all
timestamps will therefore have to avoid these primitives.

   double xtime_diff(struct xtime t1, struct xtime t2)
     ...
     return (t1.sec - t2.sec) + (t1.nsec - t2.nsec) / 1.0e9;

This implementation suffers from double-rounding, so the answer is not
always the closest to the true result.  An implementation should be
free to supply a more precise answer than the one implied by this
expression.

   struct xtime xtime_add(struct xtime t, double d)
     ... double ds;...
     t.nsec += floor(modf(d, &ds) * 1.0e9 + 0.5);
     t.sec  += ds;

First, this also suffers from multiple-rounding problems.

Second, why is that `+ 0.5' there?  strfxtime is supposed to truncate
to minus infinity, so for consistency shouldn't conversion to floating
point also truncate to minus infinity?

Third, if we really want rounding instead of truncation, the
implementation should be free to round to even (instead of rounding to
minus infinity), as round-to-even is the IEEE floating-point default
and typically gives better answers in practice.

    * Assertions:
    *
    * fabs(xtime_diff(xtime_add(t, d), t) - d) <= 0.5e-9
    *   for all t, d with fabs(t.sec + d) < 2**62 and t.nsec in the valid range

I think this assertion is false in the presence of rounding (or
truncation) errors, but I haven't checked this.  There may also be
problems with floating-point overflow on weird implementations allowed
by the C standard; I haven't checked this either (this is not of
practical importance, but the C standards nerds will care).

    * xtime_cmp(xtime_add(t, d), t)
    *   is in the set {-1, 0, 1} and has the same sign as d or is 0 iff d==0.0

This assertion is false e.g. if d == 1e-10.

So many problems in what should be simple code!  I still say that
struct xtime is way too error-prone compared to integer timestamps.
If we used integer timestamps, we wouldn't need xtime_cmp, xtime_diff,
and xtime_add at all, as <, -, and + would do the job more efficiently
and more naturally.

   This allows you to use time intervals such as 86400.0 in order to
   mean "one day later" on the UTC clock, which is what most
   applications need (and what POSIX provided so far).

This reinforces my previous suggestion that we should modify the spec
so that TIME_UTC clocks ignore leap seconds entirely.  This will make
the primitives operate more consistently, and will remove the need for
tricks like `if (t1.nsec > 1000000000) t1.nsec = 1000000000;' in user
code.

   Has anyone made some experiments or can contribute arguments to decide
   on whether passing 96-bit structs by pointer or by value is more desirable?

   Has anyone completed the UTC part of the xtime_make() specification
   code in the proposal or do I have to do this myself?

   Is anyone willing to merge the xtime text with the existing C9X
   draft and also include the change requests that Paul submitted
   to ANSI?

All these are is on my list of things to do, though I'll be proposing
the TIME_UTC variant mentioned above, so it may not match exactly what
you want.



More information about the tz mailing list