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