This is the mail archive of the
`libc-alpha@sourceware.org`
mailing list for the glibc project.

Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|

Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |

Other format: | [Raw text] |

*From*: "Albert ARIBAUD (3ADEV)" <albert dot aribaud at 3adev dot fr>*To*: libc-alpha at sourceware dot org*Cc*: "Albert ARIBAUD (3ADEV)" <albert dot aribaud at 3adev dot fr>*Date*: Wed, 20 Jun 2018 14:14:27 +0200*Subject*: [PATCH 1/1] Y2038: add function __difftime64*References*: <20180620121427.25397-1-albert.aribaud@3adev.fr>

Note: 1. The implementation expects __time64_t arguments, and could, in theory, require 64 bits to express the difference accurately; but it returns a double, which only provides about 55 significant bits. We could make it return a long double, which would be more than enough for 64 bits accuracy. But then, existing source code which uses difftime, and therefore stores difftime results in doubles, would need to change to long doubles. However, we want 64-bit time support to work without any application source code change. Besides, 55 bits allow for counting seconds accurately over 417 billion years, which is arguably enough for most actual uses of difftime. 2. The 64-bit time implementation was obtained by duplicating the original 32-bit code then simplifying the source code based on the knowledge that __time64_t is a 64-bit signed integer for all architectures. This led to the following removals: - in the subtract64 function, removal of code which handled unsigned time handling (as __time64_t is signed); - in the difftime64 function, removal of code which handled time bitsize smaller than or equal to that of a double matissa (as __time64_t has more bits than a double mantissa can hold) 3. The 32-bit implementation is now a wrapper around the 64-bit one. --- include/time.h | 6 +++ time/difftime.c | 116 ++++++++++++++++++++++++------------------------ 2 files changed, 64 insertions(+), 58 deletions(-) diff --git a/include/time.h b/include/time.h index 5afb12305e..63cc855749 100644 --- a/include/time.h +++ b/include/time.h @@ -125,6 +125,12 @@ extern char * __strptime_internal (const char *rp, const char *fmt, struct tm *tm, void *statep, locale_t locparam) attribute_hidden; +#if __TIMESIZE == 64 +# define __difftime64 __difftime +#else +extern double __difftime64 (__time64_t time1, __time64_t time0); +#endif + extern double __difftime (time_t time1, time_t time0); /* Use in the clock_* functions. Size of the field representing the diff --git a/time/difftime.c b/time/difftime.c index 7c5dd9898b..fbc7ad9d57 100644 --- a/time/difftime.c +++ b/time/difftime.c @@ -30,87 +30,75 @@ /* Return the difference between TIME1 and TIME0, where TIME0 <= TIME1. time_t is known to be an integer type. */ -static double -subtract (time_t time1, time_t time0) +static double subtract (__time64_t time1, __time64_t time0) { - if (! TYPE_SIGNED (time_t)) - return time1 - time0; - else - { - /* Optimize the common special cases where time_t - can be converted to uintmax_t without losing information. */ - uintmax_t dt = (uintmax_t) time1 - (uintmax_t) time0; - double delta = dt; - - if (UINTMAX_MAX / 2 < INTMAX_MAX) - { - /* This is a rare host where uintmax_t has padding bits, and possibly - information was lost when converting time_t to uintmax_t. - Check for overflow by comparing dt/2 to (time1/2 - time0/2). - Overflow occurred if they differ by more than a small slop. - Thanks to Clive D.W. Feather for detailed technical advice about - hosts with padding bits. + /* Optimize the common special cases where __time64_t + can be converted to uintmax_t without losing information. */ + uintmax_t dt = (uintmax_t) time1 - (uintmax_t) time0; + double delta = dt; - In the following code the "h" prefix means half. By range - analysis, we have: + if (UINTMAX_MAX / 2 < INTMAX_MAX) +{ + /* This is a rare host where uintmax_t has padding bits, and possibly + information was lost when converting time_t to uintmax_t. + Check for overflow by comparing dt/2 to (time1/2 - time0/2). + Overflow occurred if they differ by more than a small slop. + Thanks to Clive D.W. Feather for detailed technical advice about + hosts with padding bits. - -0.5 <= ht1 - 0.5*time1 <= 0.5 - -0.5 <= ht0 - 0.5*time0 <= 0.5 - -1.0 <= dht - 0.5*(time1 - time0) <= 1.0 + In the following code the "h" prefix means half. By range + analysis, we have: - If overflow has not occurred, we also have: + -0.5 <= ht1 - 0.5*time1 <= 0.5 + -0.5 <= ht0 - 0.5*time0 <= 0.5 + -1.0 <= dht - 0.5*(time1 - time0) <= 1.0 - -0.5 <= hdt - 0.5*(time1 - time0) <= 0 - -1.0 <= dht - hdt <= 1.5 + If overflow has not occurred, we also have: - and since dht - hdt is an integer, we also have: + -0.5 <= hdt - 0.5*(time1 - time0) <= 0 + -1.0 <= dht - hdt <= 1.5 - -1 <= dht - hdt <= 1 + and since dht - hdt is an integer, we also have: - or equivalently: + -1 <= dht - hdt <= 1 - 0 <= dht - hdt + 1 <= 2 + or equivalently: - In the above analysis, all the operators have their exact - mathematical semantics, not C semantics. However, dht - hdt + - 1 is unsigned in C, so it need not be compared to zero. */ + 0 <= dht - hdt + 1 <= 2 - uintmax_t hdt = dt / 2; - time_t ht1 = time1 / 2; - time_t ht0 = time0 / 2; - time_t dht = ht1 - ht0; + In the above analysis, all the operators have their exact + mathematical semantics, not C semantics. However, dht - hdt + + 1 is unsigned in C, so it need not be compared to zero. */ - if (2 < dht - hdt + 1) - { - /* Repair delta overflow. + uintmax_t hdt = dt / 2; + __time64_t ht1 = time1 / 2; + __time64_t ht0 = time0 / 2; + __time64_t dht = ht1 - ht0; - The following expression contains a second rounding, - so the result may not be the closest to the true answer. - This problem occurs only with very large differences. - It's too painful to fix this portably. */ + if (2 < dht - hdt + 1) + { + /* Repair delta overflow. - delta = dt + 2.0L * (UINTMAX_MAX - UINTMAX_MAX / 2); - } + The following expression contains a second rounding, + so the result may not be the closest to the true answer. + This problem occurs only with very large differences. + It's too painful to fix this portably. */ + + delta = dt + 2.0L * (UINTMAX_MAX - UINTMAX_MAX / 2); } +} - return delta; - } + return delta; } /* Return the difference between TIME1 and TIME0. */ double -__difftime (time_t time1, time_t time0) +__difftime64 (__time64_t time1, __time64_t time0) { - /* Convert to double and then subtract if no double-rounding error could + /* Convert to long double and then subtract if no double-rounding error could result. */ - if (TYPE_BITS (time_t) <= DBL_MANT_DIG - || (TYPE_FLOATING (time_t) && sizeof (time_t) < sizeof (long double))) - return (double) time1 - (double) time0; - - /* Likewise for long double. */ - - if (TYPE_BITS (time_t) <= LDBL_MANT_DIG || TYPE_FLOATING (time_t)) + if (TYPE_BITS (__time64_t) <= LDBL_MANT_DIG) return (long double) time1 - (long double) time0; /* Subtract the smaller integer from the larger, convert the difference to @@ -118,4 +106,16 @@ __difftime (time_t time1, time_t time0) return time1 < time0 ? - subtract (time0, time1) : subtract (time1, time0); } + +#if __TIMESIZE != 64 + +/* Return the difference between TIME1 and TIME0. */ +double +__difftime (time_t time1, time_t time0) +{ + return __difftime64 (time1, time0); +} + +#endif + strong_alias (__difftime, difftime) -- 2.17.1

**Follow-Ups**:**Re: [PATCH 1/1] Y2038: add function __difftime64***From:*Paul Eggert

**References**:**[PATCH 0/1] Y2038 support batch 3 - difftime***From:*Albert ARIBAUD (3ADEV)

Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|

Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |