|
|
1.1 ! root 1: /* ! 2: * C general utilities library. ! 3: * strtod() ! 4: * ANSI 4.10.1.4. ! 5: * Convert ASCII to double (the System V way). ! 6: * Builds significand in an unsigned long, for efficiency. ! 7: * Does not use any knowledge about floating point representation, ! 8: * except DBL_MIN_10_EXP, DBL_MAX_10_EXP, DBL_EXP_10_DIG. ! 9: */ ! 10: ! 11: #include <stdlib.h> ! 12: #include <ctype.h> ! 13: #include <errno.h> ! 14: #include <math.h> ! 15: ! 16: #if __STDC__ ! 17: #include <float.h> ! 18: #include <locale.h> ! 19: #else ! 20: #define _decimal_point '.' ! 21: #define DBL_MIN_10_EXP -37 /* DECVAX fp */ ! 22: #define DBL_MAX_10_EXP 38 ! 23: #endif ! 24: ! 25: #define DBL_EXP_10_DIG 2 /* max dec digits in legal DECVAX exponent */ ! 26: ! 27: /* Flag bits. */ ! 28: #define NEG 1 /* negative significand */ ! 29: #define DOT 2 /* decimal point seen */ ! 30: #define NEGEXP 4 /* negative exponent */ ! 31: #define BIG 8 /* significand too big for ulong */ ! 32: #define OVER 16 /* overflow */ ! 33: #define UNDER 32 /* underflow */ ! 34: ! 35: double ! 36: strtod(nptr, endptr) char *nptr; char **endptr; ! 37: { ! 38: register char *cp; ! 39: register int c, flag, eexp; ! 40: register unsigned long val; ! 41: int exp, edigits, sdigits, vdigits; ! 42: double d; ! 43: char *savcp; ! 44: ! 45: cp = nptr; ! 46: val = flag = exp = sdigits = vdigits = 0; ! 47: d = 0.; ! 48: ! 49: /* Leading white space. */ ! 50: while (isspace(c = *cp++)) ! 51: ; ! 52: ! 53: /* Optional sign. */ ! 54: switch (c) { ! 55: case '-': ! 56: flag |= NEG; ! 57: /* fall through... */ ! 58: case '+': ! 59: c = *cp++; ! 60: } ! 61: ! 62: /* Next character must be decimal digit. */ ! 63: if (!isdigit(c)) { ! 64: cp = nptr; ! 65: goto done; ! 66: } ! 67: ! 68: /* ! 69: * Significand: sequence of decimal digits with optional '.'. ! 70: * Compute chunks in val (for efficiency) until it overflows. ! 71: * d * _pow10(vdigits) + val contains the current significand. ! 72: */ ! 73: for (; ; c = *cp++) { ! 74: if (isdigit(c)) { ! 75: c -= '0'; ! 76: if (c == 0 && (flag & DOT)) { ! 77: /* Check for trailing zeros, to avoid imprecision. */ ! 78: char *look, d; ! 79: ! 80: for (look = cp; (d = *look++) == '0';) ! 81: ; ! 82: if (!isdigit(d)) { ! 83: cp = look; ! 84: c = d; ! 85: break; ! 86: } ! 87: } ! 88: if (sdigits != 0 || c != 0) ! 89: ++sdigits; /* significant digits seen */ ! 90: #if __STDC__ ! 91: if (val > (ULONG_MAX-9) / 10) { ! 92: #else ! 93: /* The pre-ANSI compiler gets the test above wrong. */ ! 94: if (val > 429496728L) { ! 95: #endif ! 96: /* Significand too big for val, use d. */ ! 97: if (flag & BIG) ! 98: d = d * _pow10(vdigits) + val; ! 99: else { ! 100: d = val; ! 101: flag |= BIG; ! 102: } ! 103: vdigits = 1; ! 104: val = c; ! 105: } else { ! 106: ++vdigits; /* decimal digits in val */ ! 107: val = val * 10 + c; ! 108: } ! 109: if (flag & DOT) ! 110: --exp; /* implicit exponent */ ! 111: } else if (c == _decimal_point && (flag & DOT) == 0) ! 112: flag |= DOT; ! 113: else ! 114: break; ! 115: } ! 116: ! 117: /* Significand to d. */ ! 118: if (flag & BIG) ! 119: d = d * _pow10(vdigits) + val; ! 120: else ! 121: d = val; ! 122: ! 123: /* Optional exponent: 'E' or 'e', optional sign, decimal digits. */ ! 124: if (c == 'e' || c == 'E') { ! 125: savcp = cp - 1; /* save in case exponent absent */ ! 126: ! 127: /* Optional sign. */ ! 128: switch (c = *cp++) { ! 129: case '-': ! 130: flag |= NEGEXP; ! 131: /* fall through... */ ! 132: case '+': ! 133: c = *cp++; ! 134: } ! 135: ! 136: /* Next character must be decimal digit. */ ! 137: if (!isdigit(c)) { ! 138: cp = savcp; /* restore pre-'E' value */ ! 139: goto done; ! 140: } ! 141: ! 142: /* Decimal digits. */ ! 143: for (eexp = edigits = 0; isdigit(c); c = *cp++) { ! 144: if (edigits != 0 || c != '0') ! 145: ++edigits; /* count exp digits for overflow */ ! 146: eexp = eexp * 10 + c - '0'; ! 147: } ! 148: if (edigits > DBL_EXP_10_DIG) { ! 149: flag |= ((flag & NEGEXP) ? UNDER : OVER); ! 150: --cp; ! 151: goto done; ! 152: } ! 153: ! 154: /* Adjust explicit exponent for digits read after '.'. */ ! 155: if (flag & NEGEXP) ! 156: exp -= eexp; ! 157: else ! 158: exp += eexp; ! 159: } ! 160: --cp; ! 161: ! 162: /* Reconcile the significand with the exponent. */ ! 163: if (exp <= DBL_MIN_10_EXP) ! 164: flag |= UNDER; /* exponent underflow */ ! 165: else if (exp + sdigits - 1 >= DBL_MAX_10_EXP) ! 166: flag |= OVER; /* exponent overflow */ ! 167: else if (exp != 0) ! 168: d *= _pow10(exp); ! 169: ! 170: done: ! 171: if (endptr != (char **)NULL) ! 172: *endptr = cp; ! 173: if (flag & UNDER) { ! 174: errno = ERANGE; ! 175: return 0.0; ! 176: } ! 177: if (flag & OVER) { ! 178: errno = ERANGE; ! 179: d = HUGE_VAL; ! 180: } ! 181: return ((flag & NEG) ? -d : d); ! 182: } ! 183: ! 184: /* end of strtod.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.