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
26static 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				 */
31static 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
64double
65strtod(
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}
255