public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: "Albert ARIBAUD (3ADEV)" <albert.aribaud@3adev.fr>
To: libc-alpha@sourceware.org
Cc: "Albert ARIBAUD (3ADEV)" <albert.aribaud@3adev.fr>
Subject: [PATCH 1/1] Y2038: add function __difftime64
Date: Wed, 20 Jun 2018 12:14:00 -0000	[thread overview]
Message-ID: <20180620121427.25397-2-albert.aribaud@3adev.fr> (raw)
In-Reply-To: <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

  reply	other threads:[~2018-06-20 12:14 UTC|newest]

Thread overview: 19+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-20 12:14 [PATCH 0/1] Y2038 support batch 3 - difftime Albert ARIBAUD (3ADEV)
2018-06-20 12:14 ` Albert ARIBAUD (3ADEV) [this message]
2018-06-20 19:29   ` [PATCH 1/1] Y2038: add function __difftime64 Paul Eggert
2018-06-20 20:55     ` Albert ARIBAUD
2018-06-21 21:17       ` Paul Eggert
2018-06-25 22:32         ` Albert ARIBAUD
2018-06-25 23:56           ` Paul Eggert
2018-06-27 11:03             ` Albert ARIBAUD
2018-07-05 18:36               ` Albert ARIBAUD
2018-07-05 19:13                 ` Zack Weinberg
2018-07-05 19:40                 ` Paul Eggert
2018-07-05 20:38                   ` Albert ARIBAUD
2018-07-05 21:17                     ` Bruno Haible
2018-07-06  5:06                       ` Albert ARIBAUD
2018-07-06 22:54                         ` Paul Eggert
2018-07-06 22:40                       ` Paul Eggert
2018-07-06 22:37                     ` Paul Eggert
2018-07-17 20:40                   ` Joseph Myers
2018-07-05 20:50                 ` time_t in gnulib Bruno Haible

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180620121427.25397-2-albert.aribaud@3adev.fr \
    --to=albert.aribaud@3adev.fr \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).