258 lines
5.7 KiB
C
258 lines
5.7 KiB
C
/*
|
||
* strtod.c --
|
||
*
|
||
* Source code for the "strtod" library procedure.
|
||
*
|
||
* Copyright (c) 1988-1993 The Regents of the University of California.
|
||
* Copyright (c) 1994 Sun Microsystems, Inc.
|
||
*
|
||
* See the file "license.terms" for information on usage and redistribution
|
||
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
||
*
|
||
* SCCS: @(#) strtod.c 1.8 96/02/15 12:08:23
|
||
*/
|
||
|
||
#include "tcl.h"
|
||
#ifdef NO_STDLIB_H
|
||
# include "compat/stdlib.h"
|
||
#else
|
||
# include <stdlib.h>
|
||
#endif
|
||
#include <ctype.h>
|
||
|
||
#ifndef TRUE
|
||
#define TRUE 1
|
||
#define FALSE 0
|
||
#endif
|
||
#ifndef NULL
|
||
#define NULL 0
|
||
#endif
|
||
|
||
static int maxExponent = 511; /* Largest possible base 10 exponent. Any
|
||
* exponent larger than this will already
|
||
* produce underflow or overflow, so there's
|
||
* no need to worry about additional digits.
|
||
*/
|
||
static double powersOf10[] = { /* Table giving binary powers of 10. Entry */
|
||
10., /* is 10^2^i. Used to convert decimal */
|
||
100., /* exponents into floating-point numbers. */
|
||
1.0e4,
|
||
1.0e8,
|
||
1.0e16,
|
||
1.0e32,
|
||
1.0e64,
|
||
1.0e128,
|
||
1.0e256
|
||
};
|
||
|
||
/*
|
||
*----------------------------------------------------------------------
|
||
*
|
||
* strtod --
|
||
*
|
||
* This procedure converts a floating-point number from an ASCII
|
||
* decimal representation to internal double-precision format.
|
||
*
|
||
* Results:
|
||
* The return value is the double-precision floating-point
|
||
* representation of the characters in string. If endPtr isn't
|
||
* NULL, then *endPtr is filled in with the address of the
|
||
* next character after the last one that was part of the
|
||
* floating-point number.
|
||
*
|
||
* Side effects:
|
||
* None.
|
||
*
|
||
*----------------------------------------------------------------------
|
||
*/
|
||
|
||
double
|
||
strtod(string, endPtr)
|
||
CONST char *string; /* A decimal ASCII floating-point number,
|
||
* optionally preceded by white space.
|
||
* Must have form "-I.FE-X", where I is the
|
||
* integer part of the mantissa, F is the
|
||
* fractional part of the mantissa, and X
|
||
* is the exponent. Either of the signs
|
||
* may be "+", "-", or omitted. Either I
|
||
* or F may be omitted, or both. The decimal
|
||
* point isn't necessary unless F is present.
|
||
* The "E" may actually be an "e". E and X
|
||
* may both be omitted (but not just one).
|
||
*/
|
||
char **endPtr; /* If non-NULL, store terminating character's
|
||
* address here. */
|
||
{
|
||
int sign, expSign = FALSE;
|
||
double fraction, dblExp, *d;
|
||
register CONST char *p;
|
||
register int c;
|
||
int exp = 0; /* Exponent read from "EX" field. */
|
||
int fracExp = 0; /* Exponent that derives from the fractional
|
||
* part. Under normal circumstatnces, it is
|
||
* the negative of the number of digits in F.
|
||
* However, if I is very long, the last digits
|
||
* of I get dropped (otherwise a long I with a
|
||
* large negative exponent could cause an
|
||
* unnecessary overflow on I alone). In this
|
||
* case, fracExp is incremented one for each
|
||
* dropped digit. */
|
||
int mantSize; /* Number of digits in mantissa. */
|
||
int decPt; /* Number of mantissa digits BEFORE decimal
|
||
* point. */
|
||
CONST char *pExp; /* Temporarily holds location of exponent
|
||
* in string. */
|
||
|
||
/*
|
||
* Strip off leading blanks and check for a sign.
|
||
*/
|
||
|
||
p = string;
|
||
while (isspace(*p)) {
|
||
p += 1;
|
||
}
|
||
if (*p == '-') {
|
||
sign = TRUE;
|
||
p += 1;
|
||
} else {
|
||
if (*p == '+') {
|
||
p += 1;
|
||
}
|
||
sign = FALSE;
|
||
}
|
||
|
||
/*
|
||
* Count the number of digits in the mantissa (including the decimal
|
||
* point), and also locate the decimal point.
|
||
*/
|
||
|
||
decPt = -1;
|
||
for (mantSize = 0; ; mantSize += 1)
|
||
{
|
||
c = *p;
|
||
if (!isdigit(c)) {
|
||
if ((c != '.') || (decPt >= 0)) {
|
||
break;
|
||
}
|
||
decPt = mantSize;
|
||
}
|
||
p += 1;
|
||
}
|
||
|
||
/*
|
||
* Now suck up the digits in the mantissa. Use two integers to
|
||
* collect 9 digits each (this is faster than using floating-point).
|
||
* If the mantissa has more than 18 digits, ignore the extras, since
|
||
* they can't affect the value anyway.
|
||
*/
|
||
|
||
pExp = p;
|
||
p -= mantSize;
|
||
if (decPt < 0) {
|
||
decPt = mantSize;
|
||
} else {
|
||
mantSize -= 1; /* One of the digits was the point. */
|
||
}
|
||
if (mantSize > 18) {
|
||
fracExp = decPt - 18;
|
||
mantSize = 18;
|
||
} else {
|
||
fracExp = decPt - mantSize;
|
||
}
|
||
if (mantSize == 0) {
|
||
fraction = 0.0;
|
||
p = string;
|
||
goto done;
|
||
} else {
|
||
int frac1, frac2;
|
||
frac1 = 0;
|
||
for ( ; mantSize > 9; mantSize -= 1)
|
||
{
|
||
c = *p;
|
||
p += 1;
|
||
if (c == '.') {
|
||
c = *p;
|
||
p += 1;
|
||
}
|
||
frac1 = 10*frac1 + (c - '0');
|
||
}
|
||
frac2 = 0;
|
||
for (; mantSize > 0; mantSize -= 1)
|
||
{
|
||
c = *p;
|
||
p += 1;
|
||
if (c == '.') {
|
||
c = *p;
|
||
p += 1;
|
||
}
|
||
frac2 = 10*frac2 + (c - '0');
|
||
}
|
||
fraction = (1.0e9 * frac1) + frac2;
|
||
}
|
||
|
||
/*
|
||
* Skim off the exponent.
|
||
*/
|
||
|
||
p = pExp;
|
||
if ((*p == 'E') || (*p == 'e')) {
|
||
p += 1;
|
||
if (*p == '-') {
|
||
expSign = TRUE;
|
||
p += 1;
|
||
} else {
|
||
if (*p == '+') {
|
||
p += 1;
|
||
}
|
||
expSign = FALSE;
|
||
}
|
||
while (isdigit(*p)) {
|
||
exp = exp * 10 + (*p - '0');
|
||
p += 1;
|
||
}
|
||
}
|
||
if (expSign) {
|
||
exp = fracExp - exp;
|
||
} else {
|
||
exp = fracExp + exp;
|
||
}
|
||
|
||
/*
|
||
* Generate a floating-point number that represents the exponent.
|
||
* Do this by processing the exponent one bit at a time to combine
|
||
* many powers of 2 of 10. Then combine the exponent with the
|
||
* fraction.
|
||
*/
|
||
|
||
if (exp < 0) {
|
||
expSign = TRUE;
|
||
exp = -exp;
|
||
} else {
|
||
expSign = FALSE;
|
||
}
|
||
if (exp > maxExponent) {
|
||
exp = maxExponent;
|
||
}
|
||
dblExp = 1.0;
|
||
for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
|
||
if (exp & 01) {
|
||
dblExp *= *d;
|
||
}
|
||
}
|
||
if (expSign) {
|
||
fraction /= dblExp;
|
||
} else {
|
||
fraction *= dblExp;
|
||
}
|
||
|
||
done:
|
||
if (endPtr != NULL) {
|
||
*endPtr = (char *) p;
|
||
}
|
||
|
||
if (sign) {
|
||
return -fraction;
|
||
}
|
||
return fraction;
|
||
}
|