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