difftime
Paul Eggert
eggert at CS.UCLA.EDU
Thu Oct 21 20:33:30 UTC 2004
"Olson, Arthur David (NIH/NCI)" <olsona at dc37a.nci.nih.gov> writes:
> + #ifndef TYPE_INTEGRAL
> + #define TYPE_INTEGRAL(type) (((type) 0.4) == 0)
> + #endif /* !defined TYPE_INTEGRAL */
A couple of nits: C99 no longer calls these "integral types"; they're
just "integer types". Also, this test is incorrect if "type" is the
C99 type "bool", since ((bool) 0.4) yields 1. Perhaps a better test
would be:
#define TYPE_IS_INTEGER(type) (((type) 0.5) != 0.5)
or something like that.
> #include "private.h" /* for TYPE_INTEGRAL and TYPE_SIGNED */
The proposed code would no longer used TYPE_SIGNED, so that part
of the comment isn't needed.
> if (sizeof (time_t) >= sizeof (double))
> return time1 - time0;
> else return (double) time1 - (double) time0;
You might want to add a comment here saying that we assume that
more-precise representations require more size. The C Standard
doesn't require this, but it's a pretty-safe assumption in practice.
> } else {
> /*
> ** time_t is integral.
> ** As elsewhere in the time zone package,
> ** use modular arithmetic to avoid overflow.
> */
> register time_t lead;
> register time_t trail;
>
> lead = time1 / 2 - time0 / 2;
This won't work if time_t is unsigned and if time1/2 < time0/2. In
that case "lead" should be negative, but the above code will compute a
positive value.
> trail = time1 % 2 - time0 % 2;
If time_t is floating, the compiler must issue a diagnostic here.
Most compilers will reject the program.
> return 2 * ((double) lead) + trail;
A minor point: it's a bit more elegant to write "return 2.0 * lead + trail;".
However, there is a more important problem with the last line: it
suffers from a double-rounding problem. In general, converting "lead"
to double will lose information, and will cause a rounding error.
Multiplying by 2 is exact (on all hosts of practical interest), but
adding "trail" will cause another rounding error.
I don't see any easy way to work around this problem.
The code that I proposed (with Clive Feather's advice about padding
bits) also suffers from a double-rounding error, but it will be far
less of a practical problem, as it can occur only on very weird hosts
with padding bits where UINTMAX_MAX / 2 < INTMAX_MAX. In contrast, I
think the double-rounding problem above can occur on ordinary hosts
with IEEE-754 floating point and 64-bit signed time_t.
There's also a efficiency problem with the current code: it uses the
integer-arithmetic approach even when it's not needed. For example,
in the common case when time_t is a 32-bit integer and "double" is
IEEE-754 double, it's faster and simpler to convert the time_t to
double and subtract the doubles, whereas the proposed approach has
some extra integer bit-twiddling and an extra floating-point
multiplication.
More information about the tz
mailing list