2 * Copyright (C) 2000 Manuel Novoa III
6 * The primary objective of this implementation was minimal size while
7 * providing robustness and resonable accuracy.
9 * This implementation depends on IEEE floating point behavior and expects
10 * to be able to generate +/- infinity as a result.
12 * There are a number of compile-time options below.
16 /*****************************************************************************/
18 /*****************************************************************************/
20 /* Set if we want to scale with a O(log2(exp)) multiplications. */
21 #define _STRTOD_LOG_SCALING 1
23 /* Set if we want strtod to set errno appropriately. */
24 /* NOTE: Implies all options below and pulls in _zero_or_inf_check. */
25 #define _STRTOD_ERRNO 0
27 /* Set if we want support for the endptr arg. */
28 /* Implied by _STRTOD_ERRNO. */
29 #define _STRTOD_ENDPTR 1
31 /* Set if we want to prevent overflow in accumulating the exponent. */
32 #define _STRTOD_RESTRICT_EXP 1
34 /* Set if we want to process mantissa digits more intelligently. */
35 /* Implied by _STRTOD_ERRNO. */
36 #define _STRTOD_RESTRICT_DIGITS 1
38 /* Set if we want to skip scaling 0 for the exponent. */
39 /* Implied by _STRTOD_ERRNO. */
40 #define _STRTOD_ZERO_CHECK 0
42 /*****************************************************************************/
43 /* Don't change anything that follows. */
44 /*****************************************************************************/
48 #undef _STRTOD_RESTRICT_EXP
49 #undef _STRTOD_RESTRICT_DIGITS
50 #undef _STRTOD_ZERO_CHECK
51 #define _STRTOD_ENDPTR 1
52 #define _STRTOD_RESTRICT_EXP 1
53 #define _STRTOD_RESTRICT_DIGITS 1
54 #define _STRTOD_ZERO_CHECK 1
57 /*****************************************************************************/
63 #if _STRTOD_RESTRICT_DIGITS
64 #define MAX_SIG_DIGITS 20
65 #define EXP_DENORM_ADJUST MAX_SIG_DIGITS
66 #define MAX_ALLOWED_EXP (MAX_SIG_DIGITS + EXP_DENORM_ADJUST - DBL_MIN_10_EXP)
68 #if DBL_DIG > MAX_SIG_DIGITS
69 #error need to adjust MAX_SIG_DIGITS
73 #if MAX_ALLOWED_EXP > INT_MAX
74 #error size assumption violated for MAX_ALLOWED_EXP
77 /* We want some excess if we're not restricting mantissa digits. */
78 #define MAX_ALLOWED_EXP ((20 - DBL_MIN_10_EXP) * 2)
82 /* Note: For i386 the macro resulted in smaller code than the function call. */
85 #define isdigit(x) ( (x >= '0') && (x <= '9') )
90 extern int _zero_or_inf_check(double x);
93 double strtod(const char *str, char **endptr)
96 #if _STRTOD_LOG_SCALING
103 char *pos = (char *) str;
107 #if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR
111 while (isspace(*pos)) { /* skip leading whitespace */
116 switch(*pos) { /* handle optional sign */
117 case '-': negative = 1; /* fall through to increment position */
122 #if _STRTOD_RESTRICT_DIGITS || _STRTOD_ENDPTR
129 while (isdigit(*pos)) { /* process string of digits */
130 #if _STRTOD_RESTRICT_DIGITS
131 if (num_digits < 0) { /* first time through? */
132 ++num_digits; /* we've now seen a digit */
134 if (num_digits || (*pos != '0')) { /* had/have nonzero */
136 if (num_digits <= MAX_SIG_DIGITS) { /* is digit significant */
137 number = number * 10. + (*pos - '0');
144 number = number * 10. + (*pos - '0');
149 if ((*pos == '.') && !pos0) { /* is this the first decimal point? */
150 pos0 = ++pos; /* save position of decimal point */
151 goto LOOP; /* and process rest of digits */
155 if (num_digits<0) { /* must have at least one digit */
161 #if _STRTOD_RESTRICT_DIGITS
162 if (num_digits > MAX_SIG_DIGITS) { /* adjust exponent for skipped digits */
163 exponent_power += num_digits - MAX_SIG_DIGITS;
168 exponent_power += pos0 - pos; /* adjust exponent for decimal point */
171 if (negative) { /* correct for sign */
173 negative = 0; /* reset for exponent processing below */
176 /* process an exponent string */
177 if (*pos == 'e' || *pos == 'E') {
181 switch(*++pos) { /* handle optional sign */
182 case '-': negative = 1; /* fall through to increment pos */
188 while (isdigit(*pos)) { /* process string of digits */
189 #if _STRTOD_RESTRICT_EXP
190 if (exponent_temp < MAX_ALLOWED_EXP) { /* overflow check */
191 exponent_temp = exponent_temp * 10 + (*pos - '0');
194 exponent_temp = exponent_temp * 10 + (*pos - '0');
200 if (pos == pos0) { /* were there no digits? */
201 pos = pos1; /* back up to e|E */
205 exponent_power -= exponent_temp;
207 exponent_power += exponent_temp;
211 #if _STRTOD_ZERO_CHECK
217 /* scale the result */
218 #if _STRTOD_LOG_SCALING
219 exponent_temp = exponent_power;
222 if (exponent_temp < 0) {
223 exponent_temp = -exponent_temp;
226 while (exponent_temp) {
227 if (exponent_temp & 1) {
228 if (exponent_power < 0) {
238 while (exponent_power) {
239 if (exponent_power < 0) {
250 if (_zero_or_inf_check(number)) {