1 /*
2 * strtod.c --
3 *
4 * Source code for the "strtod" library procedure.
5 *
6 * Copyright (c) 1988-1993 The Regents of the University of California.
7 * Copyright (c) 1994 Sun Microsystems, Inc.
8 *
9 * See the file "license.terms" for information on usage and redistribution
10 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11 */
12
13 #include "tclInt.h"
14 #include <ctype.h>
15
16 #ifndef TRUE
17 #define TRUE 1
18 #define FALSE 0
19 #endif
20 #ifndef NULL
21 #define NULL 0
22 #endif
23
24 static int maxExponent = 511; /* Largest possible base 10 exponent. Any
25 * exponent larger than this will already
26 * produce underflow or overflow, so there's
27 * no need to worry about additional digits.
28 */
29 static double powersOf10[] = { /* Table giving binary powers of 10. Entry */
30 10., /* is 10^2^i. Used to convert decimal */
31 100., /* exponents into floating-point numbers. */
32 1.0e4,
33 1.0e8,
34 1.0e16,
35 1.0e32,
36 1.0e64,
37 1.0e128,
38 1.0e256
39 };
40
41 /*
42 *----------------------------------------------------------------------
43 *
44 * strtod --
45 *
46 * This procedure converts a floating-point number from an ASCII
47 * decimal representation to internal double-precision format.
48 *
49 * Results:
50 * The return value is the double-precision floating-point
51 * representation of the characters in string. If endPtr isn't
52 * NULL, then *endPtr is filled in with the address of the
53 * next character after the last one that was part of the
54 * floating-point number.
55 *
56 * Side effects:
57 * None.
58 *
59 *----------------------------------------------------------------------
60 */
61
62 double
strtod(CONST char * string,char ** endPtr)63 strtod(
64 CONST char *string, /* A decimal ASCII floating-point number,
65 * optionally preceded by white space. Must
66 * have form "-I.FE-X", where I is the integer
67 * part of the mantissa, F is the fractional
68 * part of the mantissa, and X is the
69 * exponent. Either of the signs may be "+",
70 * "-", or omitted. Either I or F may be
71 * omitted, or both. The decimal point isn't
72 * necessary unless F is present. The "E" may
73 * actually be an "e". E and X may both be
74 * omitted (but not just one). */
75 char **endPtr) /* If non-NULL, store terminating character's
76 * address here. */
77 {
78 int sign, expSign = FALSE;
79 double fraction, dblExp, *d;
80 register CONST char *p;
81 register int c;
82 int exp = 0; /* Exponent read from "EX" field. */
83 int fracExp = 0; /* Exponent that derives from the fractional
84 * part. Under normal circumstatnces, it is
85 * the negative of the number of digits in F.
86 * However, if I is very long, the last digits
87 * of I get dropped (otherwise a long I with a
88 * large negative exponent could cause an
89 * unnecessary overflow on I alone). In this
90 * case, fracExp is incremented one for each
91 * dropped digit. */
92 int mantSize; /* Number of digits in mantissa. */
93 int decPt; /* Number of mantissa digits BEFORE decimal
94 * point. */
95 CONST char *pExp; /* Temporarily holds location of exponent in
96 * string. */
97
98 /*
99 * Strip off leading blanks and check for a sign.
100 */
101
102 p = string;
103 while (isspace(UCHAR(*p))) {
104 p += 1;
105 }
106 if (*p == '-') {
107 sign = TRUE;
108 p += 1;
109 } else {
110 if (*p == '+') {
111 p += 1;
112 }
113 sign = FALSE;
114 }
115
116 /*
117 * Count the number of digits in the mantissa (including the decimal
118 * point), and also locate the decimal point.
119 */
120
121 decPt = -1;
122 for (mantSize = 0; ; mantSize += 1)
123 {
124 c = *p;
125 if (!isdigit(c)) {
126 if ((c != '.') || (decPt >= 0)) {
127 break;
128 }
129 decPt = mantSize;
130 }
131 p += 1;
132 }
133
134 /*
135 * Now suck up the digits in the mantissa. Use two integers to collect 9
136 * digits each (this is faster than using floating-point). If the mantissa
137 * has more than 18 digits, ignore the extras, since they can't affect the
138 * value anyway.
139 */
140
141 pExp = p;
142 p -= mantSize;
143 if (decPt < 0) {
144 decPt = mantSize;
145 } else {
146 mantSize -= 1; /* One of the digits was the point. */
147 }
148 if (mantSize > 18) {
149 fracExp = decPt - 18;
150 mantSize = 18;
151 } else {
152 fracExp = decPt - mantSize;
153 }
154 if (mantSize == 0) {
155 fraction = 0.0;
156 p = string;
157 goto done;
158 } else {
159 int frac1, frac2;
160
161 frac1 = 0;
162 for ( ; mantSize > 9; mantSize -= 1) {
163 c = *p;
164 p += 1;
165 if (c == '.') {
166 c = *p;
167 p += 1;
168 }
169 frac1 = 10*frac1 + (c - '0');
170 }
171 frac2 = 0;
172 for (; mantSize > 0; mantSize -= 1) {
173 c = *p;
174 p += 1;
175 if (c == '.') {
176 c = *p;
177 p += 1;
178 }
179 frac2 = 10*frac2 + (c - '0');
180 }
181 fraction = (1.0e9 * frac1) + frac2;
182 }
183
184 /*
185 * Skim off the exponent.
186 */
187
188 p = pExp;
189 if ((*p == 'E') || (*p == 'e')) {
190 p += 1;
191 if (*p == '-') {
192 expSign = TRUE;
193 p += 1;
194 } else {
195 if (*p == '+') {
196 p += 1;
197 }
198 expSign = FALSE;
199 }
200 if (!isdigit(UCHAR(*p))) {
201 p = pExp;
202 goto done;
203 }
204 while (isdigit(UCHAR(*p))) {
205 exp = exp * 10 + (*p - '0');
206 p += 1;
207 }
208 }
209 if (expSign) {
210 exp = fracExp - exp;
211 } else {
212 exp = fracExp + exp;
213 }
214
215 /*
216 * Generate a floating-point number that represents the exponent. Do this
217 * by processing the exponent one bit at a time to combine many powers of
218 * 2 of 10. Then combine the exponent with the fraction.
219 */
220
221 if (exp < 0) {
222 expSign = TRUE;
223 exp = -exp;
224 } else {
225 expSign = FALSE;
226 }
227 if (exp > maxExponent) {
228 exp = maxExponent;
229 errno = ERANGE;
230 }
231 dblExp = 1.0;
232 for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
233 if (exp & 01) {
234 dblExp *= *d;
235 }
236 }
237 if (expSign) {
238 fraction /= dblExp;
239 } else {
240 fraction *= dblExp;
241 }
242
243 done:
244 if (endPtr != NULL) {
245 *endPtr = (char *) p;
246 }
247
248 if (sign) {
249 return -fraction;
250 }
251 return fraction;
252 }
253