Paul Eggert said:
Wow, that's pretty a complicated way to subtract two numbers. :-)
Only if you want the right answer :-)
If we can assume uintmax_t (by typedefing it on older hosts), isn't there a much simpler approach entirely?
No. [Note: my top_type is effectively that typedef.]
The idea behind the sizeof test is to avoid "long double" if it's safe to do so, since long double is expensive on some hosts.
Is it *that* expensive? I thought you were trying to avoid rounding errors.
#define TYPE_FLOATING(type) ((type) 0.5 != 0) #define TYPE_SIGNED(type) (((type) -1) < 0) #define TYPE_BIT(type) (sizeof (type) * CHAR_BIT) [...] double difftime (time_t time1, time_t time0) { if (TYPE_BIT (time_t) <= DBL_MANT_DIG
That's a conservative test I have no objection to. It's *very* conservative, since if FLT_RADIX isn't 2 it will seriously underestimate how big double is. You might be better off comparing time1 and time0 with DBL_EPSILON or use the maxLDint trick I described. But if you're worried about efficiency, why are you doing this in floating point when they're integers?
|| (TYPE_FLOATING (time_t) && sizeof (time_t) != sizeof (long double)))
Okay, this proves that time_t isn't long double. Clever.
return (double) time1 - (double) time0; if (TYPE_FLOATING (time_t)) return (long_double) time1 - (long_double) time0;
if (time1 < time0) return -simple_difftime (time0, time1); else return simple_difftime (time1, time0); }
Moved here for expositional purposes:
static double simple_difftime (time_t time1, time_t time0) { if (TYPE_SIGNED (time_t)) return (uintmax_t) time1 - (uintmax_t) time0; else return time1 - time0; }
That will sometimes get the answer badly wrong. The problem occurs when time_t is signed and the maximum value of time_t is the same as the maximum value of uintmax_t. For example, a C89 system where long is 60 bits including sign and unsigned long is 59 bits. On such systems, the maximum possible difference is greater than the maximum value of uintmax_t, and your subtract will get it wrong. I gate this case by looking for time1 >=0 and time0 < 0. In fact, you can be safer than that: #define HALFMAX ((uintmax_t)-1 >> 1) if (time1 <= HALFMAX && (time0 >= 0 || (uintmax_t) time0 >= -HALFMAX)) return (uintmax_t) time1 - (uintmax_t) time0; However, the remaining cases have to allow for overflow in the subtraction, and that's the complicated bit. -- Clive D.W. Feather | Work: <clive@demon.net> | Tel: +44 20 8495 6138 Internet Expert | Home: <clive@davros.org> | Fax: +44 870 051 9937 Demon Internet | WWW: http://www.davros.org | Mobile: +44 7973 377646 Thus plc | |