diff options
Diffstat (limited to 'lib/libc/gdtoa/strtod.c')
-rw-r--r-- | lib/libc/gdtoa/strtod.c | 94 |
1 files changed, 67 insertions, 27 deletions
diff --git a/lib/libc/gdtoa/strtod.c b/lib/libc/gdtoa/strtod.c index 66a3baa2bc3..62a6ffbf04f 100644 --- a/lib/libc/gdtoa/strtod.c +++ b/lib/libc/gdtoa/strtod.c @@ -42,16 +42,15 @@ THIS SOFTWARE. #ifndef NO_IEEE_Scale #define Avoid_Underflow #undef tinytens -/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */ +/* The factor of 2^106 in tinytens[4] helps us avoid setting the underflow */ /* flag unnecessarily. It leads to a song and dance at the end of strtod. */ static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, - 9007199254740992.e-256 + 9007199254740992.*9007199254740992.e-256 }; #endif #endif #ifdef Honor_FLT_ROUNDS -#define Rounding rounding #undef Check_FLT_ROUNDS #define Check_FLT_ROUNDS #else @@ -79,9 +78,35 @@ strtod #ifdef SET_INEXACT int inexact, oldinexact; #endif -#ifdef Honor_FLT_ROUNDS - int rounding; -#endif +#ifdef USE_LOCALE +#ifdef NO_LOCALE_CACHE + char *decimalpoint = localeconv()->decimal_point; +#else + char *decimalpoint; + static char *decimalpoint_cache; + if (!(s0 = decimalpoint_cache)) { + s0 = localeconv()->decimal_point; + if ((decimalpoint_cache = (char*)malloc(strlen(s0) + 1))) { + strcpy(decimalpoint_cache, s0); + s0 = decimalpoint_cache; + } + } + decimalpoint = (char*)s0; +#endif +#endif +#ifdef Honor_FLT_ROUNDS /*{*/ + int Rounding; +#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */ + Rounding = Flt_Rounds; +#else /*}{*/ + Rounding = 1; + switch(fegetround()) { + case FE_TOWARDZERO: Rounding = 0; break; + case FE_UPWARD: Rounding = 2; break; + case FE_DOWNWARD: Rounding = 3; + } +#endif /*}}*/ +#endif /*}*/ sign = nz0 = nz = decpt = 0; dval(rv) = 0.; @@ -107,7 +132,7 @@ strtod } break2: if (*s == '0') { -#ifndef NO_HEX_FP +#ifndef NO_HEX_FP /*{{*/ { static FPI fpi = { 53, 1-1023-53+1, 2046-1023-53+1, 1, SI }; Long exp; @@ -116,16 +141,20 @@ strtod case 'x': case 'X': { -#if defined(FE_DOWNWARD) && defined(FE_TONEAREST) && defined(FE_TOWARDZERO) && defined(FE_UPWARD) +#if defined(FE_DOWNWARD) && defined(FE_TONEAREST) && defined(FE_TOWARDZERO) && defined(FE_UPWARD) /*{{*/ FPI fpi1 = fpi; +#ifdef Honor_FLT_ROUNDS /*{{*/ + fpi1.rounding = Rounding; +#else /*}{*/ switch(fegetround()) { case FE_TOWARDZERO: fpi1.rounding = 0; break; case FE_UPWARD: fpi1.rounding = 2; break; case FE_DOWNWARD: fpi1.rounding = 3; } -#else +#endif /*}}*/ +#else /*}{*/ #define fpi1 fpi -#endif +#endif /*}}*/ switch((i = gethex(&s, &fpi1, &exp, &bb, sign)) & STRTOG_Retmask) { case STRTOG_NoNumber: s = s00; @@ -157,13 +186,17 @@ strtod z = 10*z + c - '0'; nd0 = nd; #ifdef USE_LOCALE - if (c == *localeconv()->decimal_point) + if (c == *decimalpoint) { + for(i = 1; decimalpoint[i]; ++i) + if (s[i] != decimalpoint[i]) + goto dig_done; + s += i; + c = *s; #else - if (c == '.') + if (c == '.') { + c = *++s; #endif - { decpt = 1; - c = *++s; if (!nd) { for(; c == '0'; c = *++s) nz++; @@ -192,7 +225,7 @@ strtod nz = 0; } } - } + }/*}*/ dig_done: e = 0; if (c == 'e' || c == 'E') { @@ -379,12 +412,12 @@ strtod scale = 0; #endif #ifdef Honor_FLT_ROUNDS - if ((rounding = Flt_Rounds) >= 2) { + if (Rounding >= 2) { if (sign) - rounding = rounding == 2 ? 0 : 2; + Rounding = Rounding == 2 ? 0 : 2; else - if (rounding != 2) - rounding = 0; + if (Rounding != 2) + Rounding = 0; } #endif #endif /*IEEE_Arith*/ @@ -403,7 +436,7 @@ strtod /* Can't trust HUGE_VAL */ #ifdef IEEE_Arith #ifdef Honor_FLT_ROUNDS - switch(rounding) { + switch(Rounding) { case 0: /* toward 0 */ case 3: /* toward -infinity */ word0(rv) = Big0; @@ -534,7 +567,7 @@ strtod bd2 -= bbe; bs2 = bb2; #ifdef Honor_FLT_ROUNDS - if (rounding != 1) + if (Rounding != 1) bs2++; #endif #ifdef Avoid_Underflow @@ -592,7 +625,7 @@ strtod delta->sign = 0; i = cmp(delta, bs); #ifdef Honor_FLT_ROUNDS - if (rounding != 1) { + if (Rounding != 1) { if (i < 0) { /* Error is less than an ulp */ if (!delta->x[0] && delta->wds <= 1) { @@ -602,7 +635,7 @@ strtod #endif break; } - if (rounding) { + if (Rounding) { if (dsign) { adj = 1.; goto apply_adj; @@ -648,10 +681,10 @@ strtod if (adj < 1.) adj = 1.; if (adj <= 0x7ffffffe) { - /* adj = rounding ? ceil(adj) : floor(adj); */ + /* adj = Rounding ? ceil(adj) : floor(adj); */ y = adj; if (y != adj) { - if (!((rounding>>1) ^ dsign)) + if (!((Rounding>>1) ^ dsign)) y++; adj = y; } @@ -674,8 +707,11 @@ strtod #endif /*Sudden_Underflow*/ #endif /*Avoid_Underflow*/ adj *= ulp(dval(rv)); - if (dsign) + if (dsign) { + if (word0(rv) == Big0 && word1(rv) == Big1) + goto ovfl; dval(rv) += adj; + } else dval(rv) -= adj; goto cont; @@ -768,7 +804,7 @@ strtod } #endif /*Avoid_Underflow*/ L = (word0(rv) & Exp_mask) - Exp_msk1; -#endif /*Sudden_Underflow}*/ +#endif /*Sudden_Underflow}}*/ word0(rv) = L | Bndry_mask1; word1(rv) = 0xffffffff; #ifdef IBM @@ -956,7 +992,11 @@ strtod dval(rv) *= dval(rv0); #ifndef NO_ERRNO /* try to avoid the bug of testing an 8087 register value */ +#ifdef IEEE_Arith + if (!(word0(rv) & Exp_mask)) +#else if (word0(rv) == 0 && word1(rv) == 0) +#endif errno = ERANGE; #endif } |