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