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
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
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
6980a90dddc9 merge with 1.10n5
Jim Meyering <jim@meyering.net>
parents: 310
diff changeset
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
8
311
6980a90dddc9 merge with 1.10n5
Jim Meyering <jim@meyering.net>
parents: 310
diff changeset
9 This program is distributed in the hope that it will be useful,
6980a90dddc9 merge with 1.10n5
Jim Meyering <jim@meyering.net>
parents: 310
diff changeset
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
6980a90dddc9 merge with 1.10n5
Jim Meyering <jim@meyering.net>
parents: 310
diff changeset
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6980a90dddc9 merge with 1.10n5
Jim Meyering <jim@meyering.net>
parents: 310
diff changeset
12 GNU General Public License for more details.
6980a90dddc9 merge with 1.10n5
Jim Meyering <jim@meyering.net>
parents: 310
diff changeset
13
6980a90dddc9 merge with 1.10n5
Jim Meyering <jim@meyering.net>
parents: 310
diff changeset
14 You should have received a copy of the GNU General Public License
19190
9759915b2aca all: prefer https: URLs
Paul Eggert <eggert@cs.ucla.edu>
parents: 18626
diff changeset
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
309
7900f3bbd673 remove ansidecl junk
Jim Meyering <jim@meyering.net>
parents: 308
diff changeset
16
40166
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
17 #if ! defined USE_LONG_DOUBLE
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
18 # include <config.h>
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
19 #endif
311
6980a90dddc9 merge with 1.10n5
Jim Meyering <jim@meyering.net>
parents: 310
diff changeset
20
40166
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
Jim Meyering <jim@meyering.net>
parents: 311
diff changeset
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
36
9822
fb687649f177 Add hex float support.
Eric Blake <ebb9@byu.net>
parents: 9821
diff changeset
37 #include "c-ctype.h"
fb687649f177 Add hex float support.
Eric Blake <ebb9@byu.net>
parents: 9821
diff changeset
38
40166
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
39 #undef MIN
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
40 #undef MAX
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
41 #ifdef USE_LONG_DOUBLE
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
42 # define STRTOD strtold
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
43 # define LDEXP ldexpl
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
44 # if defined __hpux && defined __hppa
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
45 /* We cannot call strtold on HP-UX/hppa, because its return type is a struct,
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
46 not a 'long double'. */
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
47 # define HAVE_UNDERLYING_STRTOD 0
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
48 # else
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
49 # define HAVE_UNDERLYING_STRTOD HAVE_STRTOLD
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
50 # endif
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
51 # define DOUBLE long double
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
52 # define MIN LDBL_MIN
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
53 # define MAX LDBL_MAX
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
54 # define L_(literal) literal##L
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
55 #else
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
56 # define STRTOD strtod
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
57 # define LDEXP ldexp
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
58 # define HAVE_UNDERLYING_STRTOD 1
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
59 # define DOUBLE double
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
60 # define MIN DBL_MIN
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
61 # define MAX DBL_MAX
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
62 # define L_(literal) literal
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
63 #endif
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
64
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
65 #if (defined USE_LONG_DOUBLE ? HAVE_LDEXPM_IN_LIBC : HAVE_LDEXP_IN_LIBC)
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
66 # define USE_LDEXP 1
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
67 #else
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
102 #if !USE_LDEXP
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
103 #undef LDEXP
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
104 #define LDEXP dummy_ldexp
13464
abaeec5957d0 strtod: Add safety check.
Bruno Haible <bruno@clisp.org>
parents: 13456
diff changeset
105 /* A dummy definition that will never be invoked. */
40166
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
106 static DOUBLE LDEXP (DOUBLE x _GL_UNUSED, int exponent _GL_UNUSED)
13464
abaeec5957d0 strtod: Add safety check.
Bruno Haible <bruno@clisp.org>
parents: 13456
diff changeset
107 {
abaeec5957d0 strtod: Add safety check.
Bruno Haible <bruno@clisp.org>
parents: 13456
diff changeset
108 abort ();
40166
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
109 return L_(0.0);
13464
abaeec5957d0 strtod: Add safety check.
Bruno Haible <bruno@clisp.org>
parents: 13456
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
115 static DOUBLE
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
125 if (USE_LDEXP && radix == 2)
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
307 /* Convert NPTR to a DOUBLE. If ENDPTR is not NULL, a pointer to the
9
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
308 character after the last one used in the number is put in *ENDPTR. */
40166
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
309 DOUBLE
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
310 STRTOD (const char *nptr, char **endptr)
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
311 #if HAVE_UNDERLYING_STRTOD
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
312 # ifdef USE_LONG_DOUBLE
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
313 # undef strtold
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
314 # else
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
315 # undef strtod
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
316 # endif
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
317 #else
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
321 #endif
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
322 /* From here on, STRTOD refers to the underlying implementation. It needs
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
323 to handle only finite unsigned decimal numbers with non-null ENDPTR. */
9
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
327
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
328 /* The number so far. */
40166
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
329 DOUBLE num;
9
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
340 ++s;
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
341
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
344 if (*s == '-' || *s == '+')
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
345 ++s;
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
346
40166
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
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
e27b495de32b strtod: port to z/OS
Daniel Richard G <skunk@iSKUNK.ORG>
parents: 18189
diff changeset
359 {
e27b495de32b strtod: port to z/OS
Daniel Richard G <skunk@iSKUNK.ORG>
parents: 18189
diff changeset
360 end = s + 1;
e27b495de32b strtod: port to z/OS
Daniel Richard G <skunk@iSKUNK.ORG>
parents: 18189
diff changeset
361
e27b495de32b strtod: port to z/OS
Daniel Richard G <skunk@iSKUNK.ORG>
parents: 18189
diff changeset
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
e27b495de32b strtod: port to z/OS
Daniel Richard G <skunk@iSKUNK.ORG>
parents: 18189
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
cdb3438ceb13 strtold: New module.
Bruno Haible <bruno@clisp.org>
parents: 40057
diff changeset
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
fb687649f177 Add hex float support.
Eric Blake <ebb9@byu.net>
parents: 9821
diff changeset
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
fb687649f177 Add hex float support.
Eric Blake <ebb9@byu.net>
parents: 9821
diff changeset
429 }
fb687649f177 Add hex float support.
Eric Blake <ebb9@byu.net>
parents: 9821
diff changeset
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
fb687649f177 Add hex float support.
Eric Blake <ebb9@byu.net>
parents: 9821
diff changeset
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
fb687649f177 Add hex float support.
Eric Blake <ebb9@byu.net>
parents: 9821
diff changeset
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
e27b495de32b strtod: port to z/OS
Daniel Richard G <skunk@iSKUNK.ORG>
parents: 18189
diff changeset
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
f8dce34b5ab0 Initial revision
Jim Meyering <jim@meyering.net>
parents:
diff changeset
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 }