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