|
|
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 (sdigits != 0 || c != 0) ! 77: ++sdigits; /* significant digits seen */ ! 78: #if __STDC__ ! 79: if (val > (ULONG_MAX-9) / 10) { ! 80: #else ! 81: /* The pre-ANSI compiler gets the test above wrong. */ ! 82: if (val > 429496728L) { ! 83: #endif ! 84: /* Significand too big for val, use d. */ ! 85: if (flag & BIG) ! 86: d = d * _pow10(vdigits) + val; ! 87: else { ! 88: d = val; ! 89: flag |= BIG; ! 90: } ! 91: vdigits = 1; ! 92: val = c; ! 93: } else { ! 94: ++vdigits; /* decimal digits in val */ ! 95: val = val * 10 + c; ! 96: } ! 97: if (flag & DOT) ! 98: --exp; /* implicit exponent */ ! 99: } else if (c == _decimal_point && (flag & DOT) == 0) ! 100: flag |= DOT; ! 101: else ! 102: break; ! 103: } ! 104: ! 105: /* Significand to d. */ ! 106: if (flag & BIG) ! 107: d = d * _pow10(vdigits) + val; ! 108: else ! 109: d = val; ! 110: ! 111: /* Optional exponent: 'E' or 'e', optional sign, decimal digits. */ ! 112: if (c == 'e' || c == 'E') { ! 113: savcp = cp - 1; /* save in case exponent absent */ ! 114: ! 115: /* Optional sign. */ ! 116: switch (c = *cp++) { ! 117: case '-': ! 118: flag |= NEGEXP; ! 119: /* fall through... */ ! 120: case '+': ! 121: c = *cp++; ! 122: } ! 123: ! 124: /* Next character must be decimal digit. */ ! 125: if (!isdigit(c)) { ! 126: cp = savcp; /* restore pre-'E' value */ ! 127: goto done; ! 128: } ! 129: ! 130: /* Decimal digits. */ ! 131: for (eexp = edigits = 0; isdigit(c); c = *cp++) { ! 132: if (edigits != 0 || c != '0') ! 133: ++edigits; /* count exp digits for overflow */ ! 134: eexp = eexp * 10 + c - '0'; ! 135: } ! 136: if (edigits > DBL_EXP_10_DIG) { ! 137: flag |= ((flag & NEGEXP) ? UNDER : OVER); ! 138: --cp; ! 139: goto done; ! 140: } ! 141: ! 142: /* Adjust explicit exponent for digits read after '.'. */ ! 143: if (flag & NEGEXP) ! 144: exp -= eexp; ! 145: else ! 146: exp += eexp; ! 147: } ! 148: --cp; ! 149: ! 150: /* Reconcile the significand with the exponent. */ ! 151: if (exp <= DBL_MIN_10_EXP) ! 152: flag |= UNDER; /* exponent underflow */ ! 153: else if (exp + sdigits - 1 >= DBL_MAX_10_EXP) ! 154: flag |= OVER; /* exponent overflow */ ! 155: else if (exp != 0) ! 156: d *= _pow10(exp); ! 157: ! 158: done: ! 159: if (endptr != (char **)NULL) ! 160: *endptr = cp; ! 161: if (flag & UNDER) { ! 162: errno = ERANGE; ! 163: return 0.0; ! 164: } ! 165: if (flag & OVER) { ! 166: errno = ERANGE; ! 167: d = HUGE_VAL; ! 168: } ! 169: return ((flag & NEG) ? -d : d); ! 170: } ! 171: ! 172: /* end of strtod.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.