X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=src%2Finternal%2Ffloatscan.c;h=da209e278e14e5abe0a39aa5cf59854696207df8;hb=bdeb184c3d08ea5017e1570e0f0431e9d7fd02fd;hp=d5444daaff8e03cf61ae93f9648e6f92129dd293;hpb=1bdd5c8b9868ebc092074e078604acb80546e43f;p=musl diff --git a/src/internal/floatscan.c b/src/internal/floatscan.c index d5444daa..da209e27 100644 --- a/src/internal/floatscan.c +++ b/src/internal/floatscan.c @@ -59,12 +59,15 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po int i, j, k, a, z; long long lrp=-1, dc=0; long long e10=0; + int lnz = 0; int gotdig = 0; int rp; int e2; long double y; long double frac=0; long double bias=0; + static const int p10s[] = { 10, 100, 1000, 10000, + 100000, 1000000, 10000000, 100000000 }; j=0; k=0; @@ -77,8 +80,9 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po if (c == '.') { if (lrp!=-1) break; lrp = dc; - } else if (k < KMAX) { + } else if (k < KMAX-2) { dc++; + if (c!='0') lnz = dc; if (j) x[k] = x[k]*10 + c-'0'; else x[k] = c-'0'; if (++j==9) { @@ -88,7 +92,7 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po gotdig=1; } else { dc++; - x[KMAX-1] |= c-'0'; + if (c!='0') x[KMAX-3] |= 1; } } if (lrp==-1) lrp=dc; @@ -114,9 +118,11 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po return 0; } - if (!x[0]) - return sign * 0.0; - if (lrp==dc && (!k || (k==1 && !j)) && (bits>30 || x[0]>>bits==0)) + /* Handle zero specially to avoid nasty special cases later */ + if (!x[0]) return sign * 0.0; + + /* Optimize small integers (w/no exponent) and over/under-flow */ + if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0)) return sign * (long double)x[0]; if (lrp > -emin/2) { errno = ERANGE; @@ -127,6 +133,7 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po return sign * LDBL_MIN * LDBL_MIN; } + /* Align incomplete final B1B digit */ if (k30 || x[0]>>bitlim==0) + return sign * (long double)x[0] * p10s[rp-10]; + } + + /* Align radix point to B1B digit boundary */ if (rp % 9) { - static const int p10s[] = { - 100000000, 10000000, 1000000, 100000, - 10000, 1000, 100, 10 - }; int rpm9 = rp>=0 ? rp%9 : rp%9+9; - int p10 = p10s[rpm9-1]; + int p10 = p10s[8-rpm9]; uint32_t carry = 0; - for (k=a; k!=z; k=(k+1 & MASK)) { + for (k=a; k!=z; k++) { uint32_t tmp = x[k] % p10; x[k] = x[k]/p10 + carry; carry = 1000000000/p10 * tmp; @@ -155,16 +168,12 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po rp -= 9; } } - if (carry) { - if ((z+1 & MASK) != a) { - x[z] = carry; - z = (z+1 & MASK); - } else x[z-1 & MASK] |= 1; - } + if (carry) x[z++] = carry; rp += 9-rpm9; } - while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[0]>sh) * tmp; if (k==a && !x[k]) { a = (a+1 & MASK); + i--; rp -= 9; } } @@ -222,6 +233,7 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po } } + /* Assemble desired bits into floating point variable */ for (y=i=0; i LDBL_MANT_DIG+e2-emin) { bits = LDBL_MANT_DIG+e2-emin; if (bits<0) bits=0; } + /* Calculate bias term to force rounding, move out lower bits */ if (bits < LDBL_MANT_DIG) { bias = copysignl(scalbn(1, 2*LDBL_MANT_DIG-bits-1), y); frac = fmodl(y, scalbn(1, LDBL_MANT_DIG-bits)); @@ -241,6 +255,7 @@ static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int po y += bias; } + /* Process tail of decimal input so it can affect rounding */ if ((a+i & MASK) != z) { uint32_t t = x[a+i & MASK]; if (t < 500000000 && (t || (a+i+1 & MASK) != z)) @@ -388,16 +403,16 @@ long double __floatscan(FILE *f, int c, int prec, int pok) switch (prec) { case 0: - bits = 24; - emin = -149; + bits = FLT_MANT_DIG; + emin = FLT_MIN_EXP-bits; break; case 1: - bits = 53; - emin = -1074; + bits = DBL_MANT_DIG; + emin = DBL_MIN_EXP-bits; break; case 2: bits = LDBL_MANT_DIG; - emin = -16445; + emin = LDBL_MIN_EXP-bits; break; default: return 0; @@ -413,9 +428,10 @@ long double __floatscan(FILE *f, int c, int prec, int pok) for (i=0; i<8 && (c|32)=="infinity"[i]; i++) if (i<7) c = shgetc(f); if (i==3 || i==8 || (i>3 && pok)) { - if (i==3) shunget(f); - if (pok) for (; i>3; i--) shunget(f); - else shlim(f, 0); + if (i!=8) { + shunget(f); + if (pok) for (; i>3; i--) shunget(f); + } return sign * INFINITY; } if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++)