Mercurial > gnulib
annotate lib/strtod.c @ 40231:9b3c79fdfe0b
strtod: fix clash with strtold
Problem reported for RHEL 5 by Jesse Caldwell (Bug#34817).
* lib/strtod.c (compute_minus_zero, minus_zero):
Simplify by remving the macro / external variable,
and having just a function. User changed. This avoids
the need for an external variable that might clash.
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Mon, 11 Mar 2019 16:40:29 -0700 |
parents | 31ab89a208b9 |
children |
rev | line source |
---|---|
40057
b06060465f09
maint: Run 'make update-copyright'
Paul Eggert <eggert@cs.ucla.edu>
parents:
19484
diff
changeset
|
1 /* Copyright (C) 1991-1992, 1997, 1999, 2003, 2006, 2008-2019 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 | |
19190 | 15 along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
309 | 16 |
40166 | 17 #if ! defined USE_LONG_DOUBLE |
18 # include <config.h> | |
19 #endif | |
311 | 20 |
40166 | 21 /* Specification. */ |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
22 #include <stdlib.h> |
373 | 23 |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
24 #include <ctype.h> /* isspace() */ |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
25 #include <errno.h> |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
26 #include <float.h> /* {DBL,LDBL}_{MIN,MAX} */ |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
27 #include <limits.h> /* LONG_{MIN,MAX} */ |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
28 #include <locale.h> /* localeconv() */ |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
29 #include <math.h> /* NAN */ |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
30 #include <stdbool.h> |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
31 #include <stdio.h> /* sprintf() */ |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
32 #include <string.h> /* strdup() */ |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
33 #if HAVE_NL_LANGINFO |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
34 # include <langinfo.h> |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
35 #endif |
9 | 36 |
9822 | 37 #include "c-ctype.h" |
38 | |
40166 | 39 #undef MIN |
40 #undef MAX | |
41 #ifdef USE_LONG_DOUBLE | |
42 # define STRTOD strtold | |
43 # define LDEXP ldexpl | |
44 # if defined __hpux && defined __hppa | |
45 /* We cannot call strtold on HP-UX/hppa, because its return type is a struct, | |
46 not a 'long double'. */ | |
47 # define HAVE_UNDERLYING_STRTOD 0 | |
48 # else | |
49 # define HAVE_UNDERLYING_STRTOD HAVE_STRTOLD | |
50 # endif | |
51 # define DOUBLE long double | |
52 # define MIN LDBL_MIN | |
53 # define MAX LDBL_MAX | |
54 # define L_(literal) literal##L | |
55 #else | |
56 # define STRTOD strtod | |
57 # define LDEXP ldexp | |
58 # define HAVE_UNDERLYING_STRTOD 1 | |
59 # define DOUBLE double | |
60 # define MIN DBL_MIN | |
61 # define MAX DBL_MAX | |
62 # define L_(literal) literal | |
63 #endif | |
64 | |
65 #if (defined USE_LONG_DOUBLE ? HAVE_LDEXPM_IN_LIBC : HAVE_LDEXP_IN_LIBC) | |
66 # define USE_LDEXP 1 | |
67 #else | |
68 # define USE_LDEXP 0 | |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
69 #endif |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
70 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
71 /* 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
|
72 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
|
73 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
|
74 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
|
75 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
76 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
|
77 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
|
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 |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
80 /* Determine the decimal-point character according to the current locale. */ |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
81 static char |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
82 decimal_point_char (void) |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
83 { |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
84 const char *point; |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
85 /* Determine it in a multithread-safe way. We know nl_langinfo is |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
86 multithread-safe on glibc systems and Mac OS X systems, but is not required |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
87 to be multithread-safe by POSIX. sprintf(), however, is multithread-safe. |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
88 localeconv() is rarely multithread-safe. */ |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
89 #if HAVE_NL_LANGINFO && (__GLIBC__ || defined __UCLIBC__ || (defined __APPLE__ && defined __MACH__)) |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
90 point = nl_langinfo (RADIXCHAR); |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
91 #elif 1 |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
92 char pointbuf[5]; |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
93 sprintf (pointbuf, "%#.0f", 1.0); |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
94 point = &pointbuf[1]; |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
95 #else |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
96 point = localeconv () -> decimal_point; |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
97 #endif |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
98 /* The decimal point is always a single byte: either '.' or ','. */ |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
99 return (point[0] != '\0' ? point[0] : '.'); |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
100 } |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
101 |
40166 | 102 #if !USE_LDEXP |
103 #undef LDEXP | |
104 #define LDEXP dummy_ldexp | |
13464 | 105 /* A dummy definition that will never be invoked. */ |
40166 | 106 static DOUBLE LDEXP (DOUBLE x _GL_UNUSED, int exponent _GL_UNUSED) |
13464 | 107 { |
108 abort (); | |
40166 | 109 return L_(0.0); |
13464 | 110 } |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
111 #endif |
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 /* 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
|
114 to ERANGE if underflow or overflow occurs. */ |
40166 | 115 static DOUBLE |
116 scale_radix_exp (DOUBLE x, int radix, long int exponent) | |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
117 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
118 /* 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
|
119 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
|
120 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
|
121 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
|
122 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
123 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
|
124 |
40166 | 125 if (USE_LDEXP && radix == 2) |
126 return LDEXP (x, e < INT_MIN ? INT_MIN : INT_MAX < e ? INT_MAX : e); | |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
127 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
128 { |
40166 | 129 DOUBLE r = x; |
13456
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 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
|
132 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
133 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
|
134 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
135 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
|
136 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
137 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
|
138 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
|
139 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
140 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
|
141 break; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
142 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
143 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
144 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
145 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
146 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
147 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
|
148 { |
40166 | 149 if (r < -MAX / radix) |
13456
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 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
|
152 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
|
153 } |
40166 | 154 else if (MAX / radix < r) |
13456
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 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
|
157 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
|
158 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
159 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
160 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
|
161 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
162 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
163 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
164 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
165 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
|
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 } |
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 /* 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
|
170 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
|
171 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
|
172 radix RADIX (either 10 or 2) exponent, and exponent character |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
173 EXPCHAR. BASE is RADIX**RADIX_MULTIPLIER. */ |
40166 | 174 static 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
|
175 parse_number (const char *nptr, |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
176 int base, int radix, int radix_multiplier, char radixchar, |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
177 char expchar, |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
178 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
|
179 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
180 const char *s = nptr; |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
181 const char *digits_start; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
182 const char *digits_end; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
183 const char *radixchar_ptr; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
184 long int exponent; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
185 DOUBLE 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
|
186 |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
187 /* First, determine the start and end of the digit sequence. */ |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
188 digits_start = s; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
189 radixchar_ptr = NULL; |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
190 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
|
191 { |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
192 if (base == 16 ? c_isxdigit (*s) : c_isdigit (*s)) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
193 ; |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
194 else if (radixchar_ptr == NULL && *s == radixchar) |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
195 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
196 /* Record that we have found the decimal point. */ |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
197 radixchar_ptr = s; |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
198 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
199 else |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
200 /* Any other character terminates the digit sequence. */ |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
201 break; |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
202 } |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
203 digits_end = s; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
204 /* Now radixchar_ptr == NULL or |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
205 digits_start <= radixchar_ptr < digits_end. */ |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
206 |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
207 if (false) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
208 { /* Unoptimized. */ |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
209 exponent = |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
210 (radixchar_ptr != NULL |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
211 ? - (long int) (digits_end - radixchar_ptr - 1) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
212 : 0); |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
213 } |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
214 else |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
215 { /* Remove trailing zero digits. This reduces rounding errors for |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
216 inputs such as 1.0000000000 or 10000000000e-10. */ |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
217 while (digits_end > digits_start) |
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 { |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
219 if (digits_end - 1 == radixchar_ptr || *(digits_end - 1) == '0') |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
220 digits_end--; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
221 else |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
222 break; |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
223 } |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
224 exponent = |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
225 (radixchar_ptr != NULL |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
226 ? (digits_end > radixchar_ptr |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
227 ? - (long int) (digits_end - radixchar_ptr - 1) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
228 : (long int) (radixchar_ptr - digits_end)) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
229 : (long int) (s - digits_end)); |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
230 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
231 |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
232 /* Then, convert the digit sequence to a number. */ |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
233 { |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
234 const char *dp; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
235 num = 0; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
236 for (dp = digits_start; dp < digits_end; dp++) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
237 if (dp != radixchar_ptr) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
238 { |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
239 int digit; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
240 |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
241 /* Make sure that multiplication by BASE will not overflow. */ |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
242 if (!(num <= MAX / base)) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
243 { |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
244 /* The value of the digit and all subsequent digits don't matter, |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
245 since we have already gotten as many digits as can be |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
246 represented in a 'DOUBLE'. This doesn't necessarily mean that |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
247 the result will overflow: The exponent may reduce it to within |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
248 range. */ |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
249 exponent += |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
250 (digits_end - dp) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
251 - (radixchar_ptr >= dp && radixchar_ptr < digits_end ? 1 : 0); |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
252 break; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
253 } |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
254 |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
255 /* Eat the next digit. */ |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
256 if (c_isdigit (*dp)) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
257 digit = *dp - '0'; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
258 else if (base == 16 && c_isxdigit (*dp)) |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
259 digit = c_tolower (*dp) - ('a' - 10); |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
260 else |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
261 abort (); |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
262 num = num * base + digit; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
263 } |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
264 } |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
265 |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
266 exponent = exponent * radix_multiplier; |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
267 |
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
268 /* Finally, parse the exponent. */ |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
269 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
|
270 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
271 /* Add any given exponent to the implicit one. */ |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
272 int saved_errno = 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
|
273 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
|
274 long int value = strtol (s + 1, &end, 10); |
40170
201ca4418b4b
strtod, strtold: Avoid unnecessary rounding errors.
Bruno Haible <bruno@clisp.org>
parents:
40169
diff
changeset
|
275 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
|
276 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
277 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
|
278 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
279 /* 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
|
280 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
|
281 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
|
282 exponent = |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
283 (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
|
284 ? (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
|
285 : (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
|
286 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
287 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
288 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
289 *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
|
290 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
|
291 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
292 |
13837
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
293 /* 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
|
294 ICC 10.0 has a bug when optimizing the expression -zero. |
40166 | 295 The expression -MIN * MIN does not work when cross-compiling |
16935
498a2211d839
Write "Mac OS X" instead of "MacOS X".
Bruno Haible <bruno@clisp.org>
parents:
16235
diff
changeset
|
296 to PowerPC on Mac OS X 10.5. */ |
40231
9b3c79fdfe0b
strtod: fix clash with strtold
Paul Eggert <eggert@cs.ucla.edu>
parents:
40172
diff
changeset
|
297 static DOUBLE |
9b3c79fdfe0b
strtod: fix clash with strtold
Paul Eggert <eggert@cs.ucla.edu>
parents:
40172
diff
changeset
|
298 minus_zero (void) |
9b3c79fdfe0b
strtod: fix clash with strtold
Paul Eggert <eggert@cs.ucla.edu>
parents:
40172
diff
changeset
|
299 { |
13837
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
300 #if defined __hpux || defined __sgi || defined __ICC |
40166 | 301 return -MIN * MIN; |
40231
9b3c79fdfe0b
strtod: fix clash with strtold
Paul Eggert <eggert@cs.ucla.edu>
parents:
40172
diff
changeset
|
302 #else |
9b3c79fdfe0b
strtod: fix clash with strtold
Paul Eggert <eggert@cs.ucla.edu>
parents:
40172
diff
changeset
|
303 return -0.0; |
9b3c79fdfe0b
strtod: fix clash with strtold
Paul Eggert <eggert@cs.ucla.edu>
parents:
40172
diff
changeset
|
304 #endif |
13837
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
305 } |
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
306 |
40166 | 307 /* Convert NPTR to a DOUBLE. If ENDPTR is not NULL, a pointer to the |
9 | 308 character after the last one used in the number is put in *ENDPTR. */ |
40166 | 309 DOUBLE |
310 STRTOD (const char *nptr, char **endptr) | |
311 #if HAVE_UNDERLYING_STRTOD | |
312 # ifdef USE_LONG_DOUBLE | |
313 # undef strtold | |
314 # else | |
315 # undef strtod | |
316 # endif | |
317 #else | |
318 # undef STRTOD | |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
319 # define STRTOD(NPTR,ENDPTR) \ |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
320 parse_number (NPTR, 10, 10, 1, radixchar, 'e', ENDPTR) |
40166 | 321 #endif |
322 /* From here on, STRTOD refers to the underlying implementation. It needs | |
323 to handle only finite unsigned decimal numbers with non-null ENDPTR. */ | |
9 | 324 { |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
325 char radixchar; |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
326 bool negative = false; |
9 | 327 |
328 /* The number so far. */ | |
40166 | 329 DOUBLE num; |
9 | 330 |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
331 const char *s = nptr; |
13545
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
332 const char *end; |
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
333 char *endbuf; |
18378
296222d9cae1
strtod: port errno handling to z/OS
Paul Eggert <eggert@cs.ucla.edu>
parents:
18377
diff
changeset
|
334 int saved_errno = errno; |
9 | 335 |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
336 radixchar = decimal_point_char (); |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
337 |
9 | 338 /* 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
|
339 while (locale_isspace (*s)) |
9 | 340 ++s; |
341 | |
342 /* Get the sign. */ | |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
343 negative = *s == '-'; |
9 | 344 if (*s == '-' || *s == '+') |
345 ++s; | |
346 | |
40166 | 347 num = STRTOD (s, &endbuf); |
13545
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
348 end = endbuf; |
9 | 349 |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
350 if (c_isdigit (s[*s == radixchar])) |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
351 { |
13487
4ccc551d5cb6
strtod: fix bug in replacement function on AIX
Eric Blake <eblake@redhat.com>
parents:
13464
diff
changeset
|
352 /* 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
|
353 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
|
354 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
|
355 '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
|
356 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
|
357 { |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
358 if (! c_isxdigit (s[2 + (s[2] == radixchar)])) |
18377 | 359 { |
360 end = s + 1; | |
361 | |
362 /* strtod() on z/OS returns ERANGE for "0x". */ | |
18378
296222d9cae1
strtod: port errno handling to z/OS
Paul Eggert <eggert@cs.ucla.edu>
parents:
18377
diff
changeset
|
363 errno = saved_errno; |
18377 | 364 } |
13507
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
365 else if (end <= s + 2) |
13545
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
366 { |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
367 num = parse_number (s + 2, 16, 2, 4, radixchar, 'p', &endbuf); |
13545
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
368 end = endbuf; |
1531149632e8
strtod: fix const diagnostic
Paul Eggert <eggert@cs.ucla.edu>
parents:
13507
diff
changeset
|
369 } |
13487
4ccc551d5cb6
strtod: fix bug in replacement function on AIX
Eric Blake <eblake@redhat.com>
parents:
13464
diff
changeset
|
370 else |
13507
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
371 { |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
372 const char *p = s + 2; |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
373 while (p < end && c_tolower (*p) != 'p') |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
374 p++; |
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
375 if (p < end && ! c_isdigit (p[1 + (p[1] == '-' || p[1] == '+')])) |
40169
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
376 { |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
377 char *dup = strdup (s); |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
378 errno = saved_errno; |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
379 if (!dup) |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
380 { |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
381 /* Not really our day, is it. Rounding errors are |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
382 better than outright failure. */ |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
383 num = |
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
384 parse_number (s + 2, 16, 2, 4, radixchar, 'p', &endbuf); |
40169
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
385 } |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
386 else |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
387 { |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
388 dup[p - s] = '\0'; |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
389 num = STRTOD (dup, &endbuf); |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
390 saved_errno = errno; |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
391 free (dup); |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
392 errno = saved_errno; |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
393 } |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
394 end = p; |
ecb43221748b
strtod, strtold: Work around HP-UX 11.31/ia64 bug.
Bruno Haible <bruno@clisp.org>
parents:
40166
diff
changeset
|
395 } |
13507
be8a41115d44
strtod: next round of AIX fixes
Eric Blake <eblake@redhat.com>
parents:
13487
diff
changeset
|
396 } |
13487
4ccc551d5cb6
strtod: fix bug in replacement function on AIX
Eric Blake <eblake@redhat.com>
parents:
13464
diff
changeset
|
397 } |
13655
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
398 else |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
399 { |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
400 /* If "1e 1" was misparsed as 10.0 instead of 1.0, re-do the |
40166 | 401 underlying STRTOD on a copy of the original string |
13655
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
402 truncated to avoid the bug. */ |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
403 const char *e = s + 1; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
404 while (e < end && c_tolower (*e) != 'e') |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
405 e++; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
406 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
|
407 { |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
408 char *dup = strdup (s); |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
409 errno = saved_errno; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
410 if (!dup) |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
411 { |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
412 /* 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
|
413 better than outright failure. */ |
40172
31ab89a208b9
strtod, strtold: Use the locale's decimal point.
Bruno Haible <bruno@clisp.org>
parents:
40170
diff
changeset
|
414 num = parse_number (s, 10, 10, 1, radixchar, 'e', &endbuf); |
13655
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
415 } |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
416 else |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
417 { |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
418 dup[e - s] = '\0'; |
40166 | 419 num = STRTOD (dup, &endbuf); |
13655
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
420 saved_errno = errno; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
421 free (dup); |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
422 errno = saved_errno; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
423 } |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
424 end = e; |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
425 } |
d813f5516d9a
strtod: work around IRIX 6.5 bug
Eric Blake <eblake@redhat.com>
parents:
13545
diff
changeset
|
426 } |
9822 | 427 |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
428 s = end; |
9822 | 429 } |
430 | |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
431 /* 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
|
432 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
|
433 && 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
|
434 && c_tolower (s[2]) == 'f') |
9822 | 435 { |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
436 s += 3; |
9822 | 437 if (c_tolower (*s) == 'i' |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9833
diff
changeset
|
438 && 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
|
439 && 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
|
440 && 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
|
441 && 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
|
442 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
|
443 num = HUGE_VAL; |
14145
a94d9a7b4aaa
strtod: Restore errno when successfully parsing Infinity or NaN.
Bruno Haible <bruno@clisp.org>
parents:
14079
diff
changeset
|
444 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
|
445 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
446 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
|
447 && 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
|
448 && 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
|
449 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
450 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
|
451 if (*s == '(') |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9833
diff
changeset
|
452 { |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
453 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
|
454 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
|
455 p++; |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
456 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
|
457 s = p + 1; |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9833
diff
changeset
|
458 } |
13456
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
459 |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
460 /* 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
|
461 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
|
462 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
|
463 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
|
464 to interpreting n-char-sequence as a hexadecimal number. */ |
18377 | 465 if (s != end || 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
|
466 num = NAN; |
14145
a94d9a7b4aaa
strtod: Restore errno when successfully parsing Infinity or NaN.
Bruno Haible <bruno@clisp.org>
parents:
14079
diff
changeset
|
467 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
|
468 } |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
469 else |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
470 { |
fd291325b6d5
strtod: make it more-accurate typically, and don't require libm
Paul R. Eggert <eggert@cs.ucla.edu>
parents:
12559
diff
changeset
|
471 /* 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
|
472 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
|
473 s = nptr; |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
474 } |
9 | 475 |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
476 if (endptr != NULL) |
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
477 *endptr = (char *) s; |
13837
d7a891a411c1
strtod: work around icc bug
Eric Blake <eblake@redhat.com>
parents:
13655
diff
changeset
|
478 /* 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
|
479 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
|
480 if (!num && negative) |
40231
9b3c79fdfe0b
strtod: fix clash with strtold
Paul Eggert <eggert@cs.ucla.edu>
parents:
40172
diff
changeset
|
481 return minus_zero (); |
9821
18bab9955c43
Document various strtod bugs, with some fixes.
Eric Blake <ebb9@byu.net>
parents:
9309
diff
changeset
|
482 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
|
483 } |