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