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} 255