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