|
|
1.1 root 1: /*
2: * C general utilities library.
3: * strtod()
4: * ANSI 4.10.1.4.
5: * Convert ASCII to double (the System V way).
6: * Builds significand in an unsigned long, for efficiency.
7: * Does not use any knowledge about floating point representation,
8: * except DBL_MIN_10_EXP, DBL_MAX_10_EXP, DBL_EXP_10_DIG.
9: */
10:
11: #include <stdlib.h>
12: #include <ctype.h>
13: #include <errno.h>
14: #include <math.h>
15:
16: #if __STDC__
17: #include <float.h>
18: #include <locale.h>
19: #else
20: #define _decimal_point '.'
21: #define DBL_MIN_10_EXP -37 /* DECVAX fp */
22: #define DBL_MAX_10_EXP 38
23: #endif
24:
25: #define DBL_EXP_10_DIG 2 /* max dec digits in legal DECVAX exponent */
26:
27: /* Flag bits. */
28: #define NEG 1 /* negative significand */
29: #define DOT 2 /* decimal point seen */
30: #define NEGEXP 4 /* negative exponent */
31: #define BIG 8 /* significand too big for ulong */
32: #define OVER 16 /* overflow */
33: #define UNDER 32 /* underflow */
34:
35: double
36: strtod(nptr, endptr) char *nptr; char **endptr;
37: {
38: register char *cp;
39: register int c, flag, eexp;
40: register unsigned long val;
41: int exp, edigits, sdigits, vdigits;
42: double d;
43: char *savcp;
44:
45: cp = nptr;
46: val = flag = exp = sdigits = vdigits = 0;
47: d = 0.;
48:
49: /* Leading white space. */
50: while (isspace(c = *cp++))
51: ;
52:
53: /* Optional sign. */
54: switch (c) {
55: case '-':
56: flag |= NEG;
57: /* fall through... */
58: case '+':
59: c = *cp++;
60: }
61:
62: /* Next character must be decimal digit. */
63: if (!isdigit(c)) {
64: cp = nptr;
65: goto done;
66: }
67:
68: /*
69: * Significand: sequence of decimal digits with optional '.'.
70: * Compute chunks in val (for efficiency) until it overflows.
71: * d * _pow10(vdigits) + val contains the current significand.
72: */
73: for (; ; c = *cp++) {
74: if (isdigit(c)) {
75: c -= '0';
76: if (c == 0 && (flag & DOT)) {
77: /* Check for trailing zeros, to avoid imprecision. */
78: char *look, d;
79:
80: for (look = cp; (d = *look++) == '0';)
81: ;
82: if (!isdigit(d)) {
83: cp = look;
84: c = d;
85: break;
86: }
87: }
88: if (sdigits != 0 || c != 0)
89: ++sdigits; /* significant digits seen */
90: #if __STDC__
91: if (val > (ULONG_MAX-9) / 10) {
92: #else
93: /* The pre-ANSI compiler gets the test above wrong. */
94: if (val > 429496728L) {
95: #endif
96: /* Significand too big for val, use d. */
97: if (flag & BIG)
98: d = d * _pow10(vdigits) + val;
99: else {
100: d = val;
101: flag |= BIG;
102: }
103: vdigits = 1;
104: val = c;
105: } else {
106: ++vdigits; /* decimal digits in val */
107: val = val * 10 + c;
108: }
109: if (flag & DOT)
110: --exp; /* implicit exponent */
111: } else if (c == _decimal_point && (flag & DOT) == 0)
112: flag |= DOT;
113: else
114: break;
115: }
116:
117: /* Significand to d. */
118: if (flag & BIG)
119: d = d * _pow10(vdigits) + val;
120: else
121: d = val;
122:
123: /* Optional exponent: 'E' or 'e', optional sign, decimal digits. */
124: if (c == 'e' || c == 'E') {
125: savcp = cp - 1; /* save in case exponent absent */
126:
127: /* Optional sign. */
128: switch (c = *cp++) {
129: case '-':
130: flag |= NEGEXP;
131: /* fall through... */
132: case '+':
133: c = *cp++;
134: }
135:
136: /* Next character must be decimal digit. */
137: if (!isdigit(c)) {
138: cp = savcp; /* restore pre-'E' value */
139: goto done;
140: }
141:
142: /* Decimal digits. */
143: for (eexp = edigits = 0; isdigit(c); c = *cp++) {
144: if (edigits != 0 || c != '0')
145: ++edigits; /* count exp digits for overflow */
146: eexp = eexp * 10 + c - '0';
147: }
148: if (edigits > DBL_EXP_10_DIG) {
149: flag |= ((flag & NEGEXP) ? UNDER : OVER);
150: --cp;
151: goto done;
152: }
153:
154: /* Adjust explicit exponent for digits read after '.'. */
155: if (flag & NEGEXP)
156: exp -= eexp;
157: else
158: exp += eexp;
159: }
160: --cp;
161:
162: /* Reconcile the significand with the exponent. */
163: if (exp <= DBL_MIN_10_EXP)
164: flag |= UNDER; /* exponent underflow */
165: else if (exp + sdigits - 1 >= DBL_MAX_10_EXP)
166: flag |= OVER; /* exponent overflow */
167: else if (exp != 0)
168: d *= _pow10(exp);
169:
170: done:
171: if (endptr != (char **)NULL)
172: *endptr = cp;
173: if (flag & UNDER) {
174: errno = ERANGE;
175: return 0.0;
176: }
177: if (flag & OVER) {
178: errno = ERANGE;
179: d = HUGE_VAL;
180: }
181: return ((flag & NEG) ? -d : d);
182: }
183:
184: /* end of strtod.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.