"Olson, Arthur David (NIH/NCI)" <olsona@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.