Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/tcl8.5.2/compat/strtod.c @ 52

Last change on this file since 52 was 25, checked in by landauf, 17 years ago

added tcl to libs

File size: 5.7 KB
Line 
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}
Note: See TracBrowser for help on using the repository browser.