Back to index

glibc  2.9
difftime.c
Go to the documentation of this file.
00001 /* Copyright (C) 1991, 1994, 1996, 2004 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003 
00004    The GNU C Library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Lesser General Public
00006    License as published by the Free Software Foundation; either
00007    version 2.1 of the License, or (at your option) any later version.
00008 
00009    The GNU C Library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Lesser General Public License for more details.
00013 
00014    You should have received a copy of the GNU Lesser General Public
00015    License along with the GNU C Library; if not, write to the Free
00016    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00017    02111-1307 USA.  */
00018 
00019 /* Written by Paul Eggert <eggert@cs.ucla.edu>.  */
00020 
00021 #include <time.h>
00022 
00023 #include <limits.h>
00024 #include <float.h>
00025 #include <stdint.h>
00026 
00027 #define TYPE_BITS(type) (sizeof (type) * CHAR_BIT)
00028 #define TYPE_FLOATING(type) ((type) 0.5 == 0.5)
00029 #define TYPE_SIGNED(type) ((type) -1 < 0)
00030 
00031 /* Return the difference between TIME1 and TIME0, where TIME0 <= TIME1.
00032    time_t is known to be an integer type.  */
00033 
00034 static double
00035 subtract (time_t time1, time_t time0)
00036 {
00037   if (! TYPE_SIGNED (time_t))
00038     return time1 - time0;
00039   else
00040     {
00041       /* Optimize the common special cases where time_t
00042         can be converted to uintmax_t without losing information.  */
00043       uintmax_t dt = (uintmax_t) time1 - (uintmax_t) time0;
00044       double delta = dt;
00045 
00046       if (UINTMAX_MAX / 2 < INTMAX_MAX)
00047        {
00048          /* This is a rare host where uintmax_t has padding bits, and possibly
00049             information was lost when converting time_t to uintmax_t.
00050             Check for overflow by comparing dt/2 to (time1/2 - time0/2).
00051             Overflow occurred if they differ by more than a small slop.
00052             Thanks to Clive D.W. Feather for detailed technical advice about
00053             hosts with padding bits.
00054 
00055             In the following code the "h" prefix means half.  By range
00056             analysis, we have:
00057 
00058                   -0.5 <= ht1 - 0.5*time1 <= 0.5
00059                   -0.5 <= ht0 - 0.5*time0 <= 0.5
00060                   -1.0 <= dht - 0.5*(time1 - time0) <= 1.0
00061 
00062              If overflow has not occurred, we also have:
00063 
00064                   -0.5 <= hdt - 0.5*(time1 - time0) <= 0
00065                   -1.0 <= dht - hdt <= 1.5
00066 
00067              and since dht - hdt is an integer, we also have:
00068 
00069                   -1 <= dht - hdt <= 1
00070 
00071              or equivalently:
00072 
00073                   0 <= dht - hdt + 1 <= 2
00074 
00075              In the above analysis, all the operators have their exact
00076              mathematical semantics, not C semantics.  However, dht - hdt +
00077              1 is unsigned in C, so it need not be compared to zero.  */
00078 
00079          uintmax_t hdt = dt / 2;
00080          time_t ht1 = time1 / 2;
00081          time_t ht0 = time0 / 2;
00082          time_t dht = ht1 - ht0;
00083 
00084          if (2 < dht - hdt + 1)
00085            {
00086              /* Repair delta overflow.
00087 
00088                The following expression contains a second rounding,
00089                so the result may not be the closest to the true answer.
00090                This problem occurs only with very large differences.
00091                It's too painful to fix this portably.  */
00092 
00093              delta = dt + 2.0L * (UINTMAX_MAX - UINTMAX_MAX / 2);
00094            }
00095        }
00096 
00097       return delta;
00098     }
00099 }
00100 
00101 /* Return the difference between TIME1 and TIME0.  */
00102 double
00103 __difftime (time_t time1, time_t time0)
00104 {
00105   /* Convert to double and then subtract if no double-rounding error could
00106      result.  */
00107 
00108   if (TYPE_BITS (time_t) <= DBL_MANT_DIG
00109       || (TYPE_FLOATING (time_t) && sizeof (time_t) < sizeof (long double)))
00110     return (double) time1 - (double) time0;
00111 
00112   /* Likewise for long double.  */
00113 
00114   if (TYPE_BITS (time_t) <= LDBL_MANT_DIG || TYPE_FLOATING (time_t))
00115     return (long double) time1 - (long double) time0;
00116 
00117   /* Subtract the smaller integer from the larger, convert the difference to
00118      double, and then negate if needed.  */
00119 
00120   return time1 < time0 ? - subtract (time0, time1) : subtract (time1, time0);
00121 }
00122 strong_alias (__difftime, difftime)