diff options
author | Martynas Venckus <martynas@cvs.openbsd.org> | 2008-12-09 19:44:11 +0000 |
---|---|---|
committer | Martynas Venckus <martynas@cvs.openbsd.org> | 2008-12-09 19:44:11 +0000 |
commit | fdb65fd80a5ceacbd684d17ad6893767c441474d (patch) | |
tree | 706246875706ed26bf03d21b04ffeb93d66d5422 /lib/libc/gdtoa/strtodg.c | |
parent | 215e2c76fd697cf5848ca1f079861699d88c764e (diff) |
bugfix update to gdtoa 2008-10-10. ok millert@, tested by many
Diffstat (limited to 'lib/libc/gdtoa/strtodg.c')
-rw-r--r-- | lib/libc/gdtoa/strtodg.c | 71 |
1 files changed, 60 insertions, 11 deletions
diff --git a/lib/libc/gdtoa/strtodg.c b/lib/libc/gdtoa/strtodg.c index 0c008737813..41ead32decb 100644 --- a/lib/libc/gdtoa/strtodg.c +++ b/lib/libc/gdtoa/strtodg.c @@ -89,7 +89,7 @@ increment(Bigint *b) return b; } - int + void #ifdef KR_headers decrement(b) Bigint *b; #else @@ -119,7 +119,6 @@ decrement(Bigint *b) *x++ = y & 0xffff; } while(borrow && x < xe); #endif - return STRTOG_Inexlo; } static int @@ -206,9 +205,9 @@ rvOK goto ret; } switch(rd) { - case 1: + case 1: /* round down (toward -Infinity) */ goto trunc; - case 2: + case 2: /* round up (toward +Infinity) */ break; default: /* round near */ k = bdif - 1; @@ -330,8 +329,24 @@ strtodg CONST char *s, *s0, *s1; double adj, adj0, rv, tol; Long L; - ULong y, z; + ULong *b, *be, y, z; Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0; +#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 irv = STRTOG_Zero; denorm = sign = nz0 = nz = 0; @@ -390,13 +405,17 @@ strtodg 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++; @@ -425,7 +444,7 @@ strtodg nz = 0; } } - } + }/*}*/ dig_done: e = 0; if (c == 'e' || c == 'E') { @@ -976,6 +995,29 @@ strtodg Bfree(bd0); Bfree(delta); if (rve > fpi->emax) { + switch(fpi->rounding & 3) { + case FPI_Round_near: + goto huge; + case FPI_Round_up: + if (!sign) + goto huge; + break; + case FPI_Round_down: + if (sign) + goto huge; + } + /* Round to largest representable magnitude */ + Bfree(rvb); + rvb = 0; + irv = STRTOG_Normal | STRTOG_Inexlo; + *exp = fpi->emax; + b = bits; + be = b + ((fpi->nbits + 31) >> 5); + while(b < be) + *b++ = -1; + if ((j = fpi->nbits & 0x1f)) + *--be >>= (32 - j); + goto ret; huge: rvb->wds = 0; irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi; @@ -990,12 +1032,19 @@ strtodg if (sudden_underflow) { rvb->wds = 0; irv = STRTOG_Underflow | STRTOG_Inexlo; +#ifndef NO_ERRNO + errno = ERANGE; +#endif } else { irv = (irv & ~STRTOG_Retmask) | (rvb->wds > 0 ? STRTOG_Denormal : STRTOG_Zero); - if (irv & STRTOG_Inexact) + if (irv & STRTOG_Inexact) { irv |= STRTOG_Underflow; +#ifndef NO_ERRNO + errno = ERANGE; +#endif + } } } if (se) |