diff options
Diffstat (limited to 'elsie.nci.nih.gov/src/difftime.c')
-rw-r--r-- | elsie.nci.nih.gov/src/difftime.c | 56 |
1 files changed, 33 insertions, 23 deletions
diff --git a/elsie.nci.nih.gov/src/difftime.c b/elsie.nci.nih.gov/src/difftime.c index 449cdf0..ba2fd03 100644 --- a/elsie.nci.nih.gov/src/difftime.c +++ b/elsie.nci.nih.gov/src/difftime.c @@ -7,42 +7,52 @@ #include "private.h" /* for time_t and TYPE_SIGNED */ +/* Return -X as a double. Using this avoids casting to 'double'. */ +static double +dminus(double x) +{ + return -x; +} + double ATTRIBUTE_CONST -difftime(const time_t time1, const time_t time0) +difftime(time_t time1, time_t time0) { /* - ** If (sizeof (double) > sizeof (time_t)) simply convert and subtract + ** If double is large enough, simply convert and subtract ** (assuming that the larger type has more precision). */ - if (sizeof (double) > sizeof (time_t)) - return (double) time1 - (double) time0; - if (!TYPE_SIGNED(time_t)) { - /* - ** The difference of two unsigned values can't overflow - ** if the minuend is greater than or equal to the subtrahend. - */ - if (time1 >= time0) - return time1 - time0; - else return -(double) (time0 - time1); + if (sizeof (time_t) < sizeof (double)) { + double t1 = time1, t0 = time0; + return t1 - t0; } + + /* + ** The difference of two unsigned values can't overflow + ** if the minuend is greater than or equal to the subtrahend. + */ + if (!TYPE_SIGNED(time_t)) + return time0 <= time1 ? time1 - time0 : dminus(time0 - time1); + + /* Use uintmax_t if wide enough. */ + if (sizeof (time_t) <= sizeof (uintmax_t)) { + uintmax_t t1 = time1, t0 = time0; + return time0 <= time1 ? t1 - t0 : dminus(t0 - t1); + } + /* ** Handle cases where both time1 and time0 have the same sign ** (meaning that their difference cannot overflow). */ if ((time1 < 0) == (time0 < 0)) - return time1 - time0; + return time1 - time0; + /* - ** time1 and time0 have opposite signs. - ** Punt if uintmax_t is too narrow. + ** The values have opposite signs and uintmax_t is too narrow. ** This suffers from double rounding; attempt to lessen that ** by using long double temporaries. */ - if (sizeof (uintmax_t) < sizeof (time_t)) - return (long double) time1 - (long double) time0; - /* - ** Stay calm...decent optimizers will eliminate the complexity below. - */ - if (time1 >= 0 /* && time0 < 0 */) - return (uintmax_t) time1 + (uintmax_t) (-1 - time0) + 1; - return -(double) ((uintmax_t) time0 + (uintmax_t) (-1 - time1) + 1); + { + long double t1 = time1, t0 = time0; + return t1 - t0; + } } |