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