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