]>
Commit | Line | Data |
---|---|---|
5b2abdfb A |
1 | /* |
2 | ** This file is in the public domain, so clarified as of | |
3 | ** June 5, 1996 by Arthur David Olson (arthur_david_olson@nih.gov). | |
4 | ** | |
5 | ** $FreeBSD: src/lib/libc/stdtime/difftime.c,v 1.4.8.1 2001/03/05 11:37:21 obrien Exp $ | |
6 | */ | |
7 | ||
8 | #ifndef lint | |
9 | #ifndef NOID | |
10 | static char elsieid[] = "@(#)difftime.c 7.7"; | |
11 | #endif /* !defined NOID */ | |
12 | #endif /* !defined lint */ | |
13 | ||
14 | /*LINTLIBRARY*/ | |
15 | ||
16 | #include "private.h" | |
17 | ||
18 | /* | |
19 | ** Algorithm courtesy Paul Eggert (eggert@twinsun.com). | |
20 | */ | |
21 | ||
22 | #ifdef HAVE_LONG_DOUBLE | |
23 | #define long_double long double | |
24 | #endif /* defined HAVE_LONG_DOUBLE */ | |
25 | #ifndef HAVE_LONG_DOUBLE | |
26 | #define long_double double | |
27 | #endif /* !defined HAVE_LONG_DOUBLE */ | |
28 | ||
29 | double | |
30 | difftime(time1, time0) | |
31 | const time_t time1; | |
32 | const time_t time0; | |
33 | { | |
34 | time_t delta; | |
35 | time_t hibit; | |
36 | ||
37 | if (sizeof(time_t) < sizeof(double)) | |
38 | return (double) time1 - (double) time0; | |
39 | if (sizeof(time_t) < sizeof(long_double)) | |
40 | return (long_double) time1 - (long_double) time0; | |
41 | if (time1 < time0) | |
42 | return -difftime(time0, time1); | |
43 | /* | |
44 | ** As much as possible, avoid loss of precision | |
45 | ** by computing the difference before converting to double. | |
46 | */ | |
47 | delta = time1 - time0; | |
48 | if (delta >= 0) | |
49 | return delta; | |
50 | /* | |
51 | ** Repair delta overflow. | |
52 | */ | |
53 | hibit = (~ (time_t) 0) << (TYPE_BIT(time_t) - 1); | |
54 | /* | |
55 | ** The following expression rounds twice, which means | |
56 | ** the result may not be the closest to the true answer. | |
57 | ** For example, suppose time_t is 64-bit signed int, | |
58 | ** long_double is IEEE 754 double with default rounding, | |
59 | ** time1 = 9223372036854775807 and time0 = -1536. | |
60 | ** Then the true difference is 9223372036854777343, | |
61 | ** which rounds to 9223372036854777856 | |
62 | ** with a total error of 513. | |
63 | ** But delta overflows to -9223372036854774273, | |
64 | ** which rounds to -9223372036854774784, and correcting | |
65 | ** this by subtracting 2 * (long_double) hibit | |
66 | ** (i.e. by adding 2**64 = 18446744073709551616) | |
67 | ** yields 9223372036854776832, which | |
68 | ** rounds to 9223372036854775808 | |
69 | ** with a total error of 1535 instead. | |
70 | ** This problem occurs only with very large differences. | |
71 | ** It's too painful to fix this portably. | |
72 | ** We are not alone in this problem; | |
73 | ** some C compilers round twice when converting | |
74 | ** large unsigned types to small floating types, | |
75 | ** so if time_t is unsigned the "return delta" above | |
76 | ** has the same double-rounding problem with those compilers. | |
77 | */ | |
78 | return delta - 2 * (long_double) hibit; | |
79 | } |