Version:
~ [ 7.14.9 ] ~
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 29250 2007-11-06 21:35:32Z erikgreenwald $
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 - '');
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 - '');
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 - '');
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 }
255
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.