Mercurial > gnulib
annotate lib/strtod.c @ 16235:18a38c9615f0
In commentary, do not use ` to quote.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Thu, 05 Jan 2012 23:53:49 -0800 |
parents | 8250f2777afc |
children | 498a2211d839 |
rev | line source |
---|---|
16201
8250f2777afc
maint: update all copyright year number ranges
Jim Meyering <meyering@redhat.com>
parents:
14145
diff
changeset
|
1 /* Copyright (C) 1991-1992, 1997, 1999, 2003, 2006, 2008-2012 Free Software |
12559
c2cbabec01dd
update nearly all FSF copyright year lists to include 2010
Jim Meyering <meyering@redhat.com>
parents:
12422
diff
changeset
|
2 Foundation, Inc. |
9 | 3 |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
4 This program is free software: you can redistribute it and/or modify |
311 | 5 it under the terms of the GNU General Public License as published by |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
6 the Free Software Foundation; either version 3 of the License, or |
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
7 (at your option) any later version. |
9 | 8 |
311 | 9 This program is distributed in the hope that it will be useful, |
10 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 GNU General Public License for more details. | |
13 | |
14 You should have received a copy of the GNU General Public License | |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7302
diff
changeset
|
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
309 | 16 |
7302
8a1a9361108c
* _fpending.c: Include <config.h> unconditionally, since we no
Paul Eggert <eggert@cs.ucla.edu>
parents:
6930
diff
changeset
|
17 #include <config.h> |
311 | 18 |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
19 #include <stdlib.h> |
373 | 20 |
311 | 21 #include <ctype.h> |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
22 #include <errno.h> |
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
23 #include <float.h> |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
24 #include <limits.h> |
311 | 25 #include <math.h> |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
26 #include <stdbool.h> |
13655
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
27 #include <string.h> |
9 | 28 |
9822 | 29 #include "c-ctype.h" |
30 | |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
31 #ifndef HAVE_LDEXP_IN_LIBC |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
32 #define HAVE_LDEXP_IN_LIBC 0 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
33 #endif |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
34 #ifndef HAVE_RAW_DECL_STRTOD |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
35 #define HAVE_RAW_DECL_STRTOD 0 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
36 #endif |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
37 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
38 /* Return true if C is a space in the current locale, avoiding |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
39 problems with signed char and isspace. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
40 static bool |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
41 locale_isspace (char c) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
42 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
43 unsigned char uc = c; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
44 return isspace (uc) != 0; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
45 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
46 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
47 #if !HAVE_LDEXP_IN_LIBC |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
48 #define ldexp dummy_ldexp |
13464 | 49 /* A dummy definition that will never be invoked. */ |
50 static double ldexp (double x _GL_UNUSED, int exponent _GL_UNUSED) | |
51 { | |
52 abort (); | |
53 return 0.0; | |
54 } | |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
55 #endif |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
56 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
57 /* Return X * BASE**EXPONENT. Return an extreme value and set errno |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
58 to ERANGE if underflow or overflow occurs. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
59 static double |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
60 scale_radix_exp (double x, int radix, long int exponent) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
61 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
62 /* If RADIX == 10, this code is neither precise nor fast; it is |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
63 merely a straightforward and relatively portable approximation. |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
64 If N == 2, this code is precise on a radix-2 implementation, |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
65 albeit perhaps not fast if ldexp is not in libc. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
66 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
67 long int e = exponent; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
68 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
69 if (HAVE_LDEXP_IN_LIBC && radix == 2) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
70 return ldexp (x, e < INT_MIN ? INT_MIN : INT_MAX < e ? INT_MAX : e); |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
71 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
72 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
73 double r = x; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
74 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
75 if (r != 0) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
76 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
77 if (e < 0) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
78 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
79 while (e++ != 0) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
80 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
81 r /= radix; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
82 if (r == 0 && x != 0) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
83 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
84 errno = ERANGE; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
85 break; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
86 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
87 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
88 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
89 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
90 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
91 while (e-- != 0) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
92 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
93 if (r < -DBL_MAX / radix) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
94 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
95 errno = ERANGE; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
96 return -HUGE_VAL; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
97 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
98 else if (DBL_MAX / radix < r) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
99 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
100 errno = ERANGE; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
101 return HUGE_VAL; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
102 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
103 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
104 r *= radix; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
105 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
106 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
107 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
108 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
109 return r; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
110 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
111 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
112 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
113 /* Parse a number at NPTR; this is a bit like strtol (NPTR, ENDPTR) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
114 except there are no leading spaces or signs or "0x", and ENDPTR is |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
115 nonnull. The number uses a base BASE (either 10 or 16) fraction, a |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
116 radix RADIX (either 10 or 2) exponent, and exponent character |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
117 EXPCHAR. To convert from a number of digits to a radix exponent, |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
118 multiply by RADIX_MULTIPLIER (either 1 or 4). */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
119 static double |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
120 parse_number (const char *nptr, |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
121 int base, int radix, int radix_multiplier, char expchar, |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
122 char **endptr) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
123 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
124 const char *s = nptr; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
125 bool got_dot = false; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
126 long int exponent = 0; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
127 double num = 0; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
128 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
129 for (;; ++s) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
130 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
131 int digit; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
132 if (c_isdigit (*s)) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
133 digit = *s - '0'; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
134 else if (base == 16 && c_isxdigit (*s)) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
135 digit = c_tolower (*s) - ('a' - 10); |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
136 else if (! got_dot && *s == '.') |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
137 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
138 /* Record that we have found the decimal point. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
139 got_dot = true; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
140 continue; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
141 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
142 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
143 /* Any other character terminates the number. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
144 break; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
145 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
146 /* Make sure that multiplication by base will not overflow. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
147 if (num <= DBL_MAX / base) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
148 num = num * base + digit; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
149 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
150 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
151 /* The value of the digit doesn't matter, since we have already |
16235
18a38c9615f0
In commentary, do not use ` to quote.
Paul Eggert <eggert@cs.ucla.edu>
parents:
16201
diff
changeset
|
152 gotten as many digits as can be represented in a 'double'. |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
153 This doesn't necessarily mean the result will overflow. |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
154 The exponent may reduce it to within range. |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
155 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
156 We just need to record that there was another |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
157 digit so that we can multiply by 10 later. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
158 exponent += radix_multiplier; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
159 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
160 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
161 /* Keep track of the number of digits after the decimal point. |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
162 If we just divided by base here, we might lose precision. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
163 if (got_dot) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
164 exponent -= radix_multiplier; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
165 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
166 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
167 if (c_tolower (*s) == expchar && ! locale_isspace (s[1])) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
168 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
169 /* Add any given exponent to the implicit one. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
170 int save = errno; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
171 char *end; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
172 long int value = strtol (s + 1, &end, 10); |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
173 errno = save; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
174 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
175 if (s + 1 != end) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
176 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
177 /* Skip past the exponent, and add in the implicit exponent, |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
178 resulting in an extreme value on overflow. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
179 s = end; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
180 exponent = |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
181 (exponent < 0 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
182 ? (value < LONG_MIN - exponent ? LONG_MIN : exponent + value) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
183 : (LONG_MAX - exponent < value ? LONG_MAX : exponent + value)); |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
184 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
185 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
186 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
187 *endptr = (char *) s; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
188 return scale_radix_exp (num, radix, exponent); |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
189 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
190 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
191 static double underlying_strtod (const char *, char **); |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
192 |
13837
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
193 /* HP cc on HP-UX 10.20 has a bug with the constant expression -0.0. |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
194 ICC 10.0 has a bug when optimizing the expression -zero. |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
195 The expression -DBL_MIN * DBL_MIN does not work when cross-compiling |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
196 to PowerPC on MacOS X 10.5. */ |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
197 #if defined __hpux || defined __sgi || defined __ICC |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
198 static double |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
199 compute_minus_zero (void) |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
200 { |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
201 return -DBL_MIN * DBL_MIN; |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
202 } |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
203 # define minus_zero compute_minus_zero () |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
204 #else |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
205 double minus_zero = -0.0; |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
206 #endif |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
207 |
9 | 208 /* Convert NPTR to a double. If ENDPTR is not NULL, a pointer to the |
209 character after the last one used in the number is put in *ENDPTR. */ | |
210 double | |
1691 | 211 strtod (const char *nptr, char **endptr) |
9 | 212 { |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
213 bool negative = false; |
9 | 214 |
215 /* The number so far. */ | |
216 double num; | |
217 | |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
218 const char *s = nptr; |
13545
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
219 const char *end; |
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
220 char *endbuf; |
13655
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
221 int saved_errno; |
9 | 222 |
223 /* Eat whitespace. */ | |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
224 while (locale_isspace (*s)) |
9 | 225 ++s; |
226 | |
227 /* Get the sign. */ | |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
228 negative = *s == '-'; |
9 | 229 if (*s == '-' || *s == '+') |
230 ++s; | |
231 | |
13655
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
232 saved_errno = errno; |
13545
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
233 num = underlying_strtod (s, &endbuf); |
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
234 end = endbuf; |
9 | 235 |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
236 if (c_isdigit (s[*s == '.'])) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
237 { |
13487
4ccc551d5cb6
strtod: fix bug in replacement function on AIX
Eric Blake <eblake@redhat.com>
parents:
13464
diff
changeset
|
238 /* If a hex float was converted incorrectly, do it ourselves. |
13507
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
239 If the string starts with "0x" but does not contain digits, |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
240 consume the "0" ourselves. If a hex float is followed by a |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
241 'p' but no exponent, then adjust the end pointer. */ |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
242 if (*s == '0' && c_tolower (s[1]) == 'x') |
13487
4ccc551d5cb6
strtod: fix bug in replacement function on AIX
Eric Blake <eblake@redhat.com>
parents:
13464
diff
changeset
|
243 { |
13507
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
244 if (! c_isxdigit (s[2 + (s[2] == '.')])) |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
245 end = s + 1; |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
246 else if (end <= s + 2) |
13545
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
247 { |
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
248 num = parse_number (s + 2, 16, 2, 4, 'p', &endbuf); |
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
249 end = endbuf; |
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
250 } |
13487
4ccc551d5cb6
strtod: fix bug in replacement function on AIX
Eric Blake <eblake@redhat.com>
parents:
13464
diff
changeset
|
251 else |
13507
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
252 { |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
253 const char *p = s + 2; |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
254 while (p < end && c_tolower (*p) != 'p') |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
255 p++; |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
256 if (p < end && ! c_isdigit (p[1 + (p[1] == '-' || p[1] == '+')])) |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
257 end = p; |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
258 } |
13487
4ccc551d5cb6
strtod: fix bug in replacement function on AIX
Eric Blake <eblake@redhat.com>
parents:
13464
diff
changeset
|
259 } |
13655
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
260 else |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
261 { |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
262 /* If "1e 1" was misparsed as 10.0 instead of 1.0, re-do the |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
263 underlying strtod on a copy of the original string |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
264 truncated to avoid the bug. */ |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
265 const char *e = s + 1; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
266 while (e < end && c_tolower (*e) != 'e') |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
267 e++; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
268 if (e < end && ! c_isdigit (e[1 + (e[1] == '-' || e[1] == '+')])) |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
269 { |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
270 char *dup = strdup (s); |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
271 errno = saved_errno; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
272 if (!dup) |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
273 { |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
274 /* Not really our day, is it. Rounding errors are |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
275 better than outright failure. */ |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
276 num = parse_number (s, 10, 10, 1, 'e', &endbuf); |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
277 } |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
278 else |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
279 { |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
280 dup[e - s] = '\0'; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
281 num = underlying_strtod (dup, &endbuf); |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
282 saved_errno = errno; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
283 free (dup); |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
284 errno = saved_errno; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
285 } |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
286 end = e; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
287 } |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
288 } |
9822 | 289 |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
290 s = end; |
9822 | 291 } |
292 | |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
293 /* Check for infinities and NaNs. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
294 else if (c_tolower (*s) == 'i' |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
295 && c_tolower (s[1]) == 'n' |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
296 && c_tolower (s[2]) == 'f') |
9822 | 297 { |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
298 s += 3; |
9822 | 299 if (c_tolower (*s) == 'i' |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9833
diff
changeset
|
300 && c_tolower (s[1]) == 'n' |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
301 && c_tolower (s[2]) == 'i' |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
302 && c_tolower (s[3]) == 't' |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
303 && c_tolower (s[4]) == 'y') |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
304 s += 5; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
305 num = HUGE_VAL; |
14145
a94d9a7b4aaa
strtod: Restore errno when successfully parsing Infinity or NaN.
Bruno Haible <bruno@clisp.org>
parents:
14079
diff
changeset
|
306 errno = saved_errno; |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
307 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
308 else if (c_tolower (*s) == 'n' |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
309 && c_tolower (s[1]) == 'a' |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
310 && c_tolower (s[2]) == 'n') |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
311 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
312 s += 3; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
313 if (*s == '(') |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9833
diff
changeset
|
314 { |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
315 const char *p = s + 1; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
316 while (c_isalnum (*p)) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
317 p++; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
318 if (*p == ')') |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
319 s = p + 1; |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9833
diff
changeset
|
320 } |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
321 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
322 /* If the underlying implementation misparsed the NaN, assume |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
323 its result is incorrect, and return a NaN. Normally it's |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
324 better to use the underlying implementation's result, since a |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
325 nice implementation populates the bits of the NaN according |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
326 to interpreting n-char-sequence as a hexadecimal number. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
327 if (s != end) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
328 num = NAN; |
14145
a94d9a7b4aaa
strtod: Restore errno when successfully parsing Infinity or NaN.
Bruno Haible <bruno@clisp.org>
parents:
14079
diff
changeset
|
329 errno = saved_errno; |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
330 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
331 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
332 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
333 /* No conversion could be performed. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
334 errno = EINVAL; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
335 s = nptr; |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
336 } |
9 | 337 |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
338 if (endptr != NULL) |
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
339 *endptr = (char *) s; |
13837
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
340 /* Special case -0.0, since at least ICC miscompiles negation. We |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
341 can't use copysign(), as that drags in -lm on some platforms. */ |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
342 if (!num && negative) |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
343 return minus_zero; |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
344 return negative ? -num : num; |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
345 } |
9 | 346 |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
347 /* The "underlying" strtod implementation. This must be defined |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
348 after strtod because it #undefs strtod. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
349 static double |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
350 underlying_strtod (const char *nptr, char **endptr) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
351 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
352 if (HAVE_RAW_DECL_STRTOD) |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
353 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
354 /* Prefer the native strtod if available. Usually it should |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
355 work and it should give more-accurate results than our |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
356 approximation. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
357 #undef strtod |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
358 return strtod (nptr, endptr); |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
359 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
360 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
361 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
362 /* Approximate strtod well enough for this module. There's no |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
363 need to handle anything but finite unsigned decimal |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
364 numbers with nonnull ENDPTR. */ |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
365 return parse_number (nptr, 10, 10, 1, 'e', endptr); |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
366 } |
9 | 367 } |