]> pd.if.org Git - pdclib/commitdiff
Using code from tzcode.
authorMartin Baute <solar@rootdirectory.de>
Tue, 5 Apr 2016 05:47:32 +0000 (07:47 +0200)
committerMartin Baute <solar@rootdirectory.de>
Tue, 5 Apr 2016 05:47:32 +0000 (07:47 +0200)
functions/time/difftime.c
internals/_PDCLIB_aux.h
platform/example/internals/_PDCLIB_config.h

index fa6eb9c7f741cfeb0fd12fa1a5b520cc6c4a828d..b76efb95e81aa5af04a4c8248e74bc328f293c84 100644 (file)
 
 double difftime( time_t time1, time_t time0 )
 {
-    return ( time1 > time0 ) ? (double)( time1 - time0 ) : -(double)( time0 - time1 );
+    /* If we want to avoid rounding errors and overflows, we need to be
+       careful with the exact type of time_t being unknown to us.
+       The code below is based on tzcode's difftime.c, which is in the
+       public domain, so clarified as of 1996-06-05 by Arthur David Olson.
+    */
+
+    /* If double is large enough, simply covert and substract
+       (assuming that the larger type has more precision).
+    */
+    if ( sizeof( time_t ) < sizeof( double ) )
+    {
+        return (double)time1 - (double)time0;
+    }
+
+    /* The difference of two unsigned values cannot overflow if the
+       minuend is greater or equal to the subtrahend.
+    */
+    if ( ! _PDCLIB_TYPE_SIGNED( time_t ) )
+    {
+        return ( time1 >= time0 ) ? (double)( time1 - time0 ) : -(double)( time0 - time1 );
+    }
+
+    /* Use uintmax_t if wide enough. */
+    if ( sizeof( time_t ) <= sizeof( _PDCLIB_uintmax_t ) )
+    {
+        _PDCLIB_uintmax_t t1 = time1, t0 = time0;
+        return ( time1 >= time0 ) ? t1 - t0 : -(double)( t0 - t1 );
+    }
+
+    /* If both times have the same sign, their difference cannot overflow. */
+    if ( ( time1 < 0 ) == ( time0 < 0 ) )
+    {
+        return time1 - time0;
+    }
+
+    /* The times have opposite signs, and uintmax_t is too narrow.
+       This suffers from double rounding; attempt to lessen that
+       by using long double temporaries.
+    */
+    long double t1 = time1, t0 = time0;
+    return t1 - t0;
 }
 
 #endif
index d09c9e7355b1bbfce6156fa650fe9c2779508dec..ebbced4abc8658b3c312b2d4b7b5a984ecfb65ef 100644 (file)
@@ -47,6 +47,9 @@
 /* _PDCLIB_concat( x, y ) concatenates two preprocessor tokens with extending */
 /* _PDCLIB_static_assert( e, m ) does a compile-time assertion of expression  */
 /*                               e, with m as the failure message.            */
+/* _PDCLIB_TYPE_SIGNED( type ) resolves to true if type is signed.            */
+/* _PDCLIB_TWOS_COMPLEMENT( type ) resolves to true if two's complement is    */
+/*                                 used for type.                             */
 /* -------------------------------------------------------------------------- */
 
 #define _PDCLIB_cc( x, y )     x ## y
@@ -54,6 +57,9 @@
 
 #define _PDCLIB_static_assert( e, m ) enum { _PDCLIB_concat( _PDCLIB_assert_, __LINE__ ) = 1 / ( !!(e) ) }
 
+#define _PDCLIB_TYPE_SIGNED( type ) (((type) -1) < 0)
+#define _PDCLIB_TWOS_COMPLEMENT( type ) ((type) ~ (type) 0 < 0 )
+
 #define _PDCLIB_symbol2value( x ) #x
 #define _PDCLIB_symbol2string( x ) _PDCLIB_symbol2value( x )
 
index 41fe9e0a394bcb757004000824fb636acd0ffaf1..fe23663244a3c29ebace87258ed06a69e53452b1 100755 (executable)
@@ -176,7 +176,6 @@ struct _PDCLIB_imaxdiv_t
 
 /* See <time.h> for a couple of comments on these types and their semantics. */
 
-/* If you change this type to something exotic, check time/difftime.c */
 #define _PDCLIB_time long
 
 #define _PDCLIB_clock long