OSDN Git Service

Updated to tcl 8.4.1
[pf3gnuchains/sourceware.git] / tcl / compat / strtod.c
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$
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
27 static 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                                  */
32 static 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 \f
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
65 double
66 strtod(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
249 done:
250     if (endPtr != NULL) {
251         *endPtr = (char *) p;
252     }
253
254     if (sign) {
255         return -fraction;
256     }
257     return fraction;
258 }