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