|
|
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 (sdigits != 0 || c != 0)
77: ++sdigits; /* significant digits seen */
78: #if __STDC__
79: if (val > (ULONG_MAX-9) / 10) {
80: #else
81: /* The pre-ANSI compiler gets the test above wrong. */
82: if (val > 429496728L) {
83: #endif
84: /* Significand too big for val, use d. */
85: if (flag & BIG)
86: d = d * _pow10(vdigits) + val;
87: else {
88: d = val;
89: flag |= BIG;
90: }
91: vdigits = 1;
92: val = c;
93: } else {
94: ++vdigits; /* decimal digits in val */
95: val = val * 10 + c;
96: }
97: if (flag & DOT)
98: --exp; /* implicit exponent */
99: } else if (c == _decimal_point && (flag & DOT) == 0)
100: flag |= DOT;
101: else
102: break;
103: }
104:
105: /* Significand to d. */
106: if (flag & BIG)
107: d = d * _pow10(vdigits) + val;
108: else
109: d = val;
110:
111: /* Optional exponent: 'E' or 'e', optional sign, decimal digits. */
112: if (c == 'e' || c == 'E') {
113: savcp = cp - 1; /* save in case exponent absent */
114:
115: /* Optional sign. */
116: switch (c = *cp++) {
117: case '-':
118: flag |= NEGEXP;
119: /* fall through... */
120: case '+':
121: c = *cp++;
122: }
123:
124: /* Next character must be decimal digit. */
125: if (!isdigit(c)) {
126: cp = savcp; /* restore pre-'E' value */
127: goto done;
128: }
129:
130: /* Decimal digits. */
131: for (eexp = edigits = 0; isdigit(c); c = *cp++) {
132: if (edigits != 0 || c != '0')
133: ++edigits; /* count exp digits for overflow */
134: eexp = eexp * 10 + c - '0';
135: }
136: if (edigits > DBL_EXP_10_DIG) {
137: flag |= ((flag & NEGEXP) ? UNDER : OVER);
138: --cp;
139: goto done;
140: }
141:
142: /* Adjust explicit exponent for digits read after '.'. */
143: if (flag & NEGEXP)
144: exp -= eexp;
145: else
146: exp += eexp;
147: }
148: --cp;
149:
150: /* Reconcile the significand with the exponent. */
151: if (exp <= DBL_MIN_10_EXP)
152: flag |= UNDER; /* exponent underflow */
153: else if (exp + sdigits - 1 >= DBL_MAX_10_EXP)
154: flag |= OVER; /* exponent overflow */
155: else if (exp != 0)
156: d *= _pow10(exp);
157:
158: done:
159: if (endptr != (char **)NULL)
160: *endptr = cp;
161: if (flag & UNDER) {
162: errno = ERANGE;
163: return 0.0;
164: }
165: if (flag & OVER) {
166: errno = ERANGE;
167: d = HUGE_VAL;
168: }
169: return ((flag & NEG) ? -d : d);
170: }
171:
172: /* end of strtod.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.