4
0
mirror of git://sourceware.org/git/newlib-cygwin.git synced 2025-02-11 19:49:15 +08:00

* libc/stdlib/strtod.c: Manual update to latest algorithm from NetBSD.

This commit is contained in:
Corinna Vinschen 2013-04-24 10:21:16 +00:00
parent 09caddaaf5
commit 6fb85adeac
2 changed files with 122 additions and 38 deletions

View File

@ -1,3 +1,8 @@
2013-04-24 Corinna Vinschen <vinschen@redhat.com>
Nick Clifton <nickc@redhat.com>
* libc/stdlib/strtod.c: Manual update to latest algorithm from NetBSD.
2013-04-23 Corinna Vinschen <vinschen@redhat.com> 2013-04-23 Corinna Vinschen <vinschen@redhat.com>
Port newlib to x86_64-pc-cygwin. Port newlib to x86_64-pc-cygwin.

View File

@ -128,11 +128,17 @@ THIS SOFTWARE.
#ifndef NO_IEEE_Scale #ifndef NO_IEEE_Scale
#define Avoid_Underflow #define Avoid_Underflow
#undef tinytens #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. */ /* 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, static _CONST double tinytens[] = { 1e-16, 1e-32,
9007199254740992.e-256 #ifdef _DOUBLE_IS_32BITS
0.0, 0.0, 0.0
#else
1e-64, 1e-128,
9007199254740992. * 9007199254740992.e-256
#endif
}; };
#endif #endif
#endif #endif
@ -144,6 +150,28 @@ static _CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
#define Rounding Flt_Rounds #define Rounding Flt_Rounds
#endif #endif
#ifdef Avoid_Underflow /*{*/
static double
_DEFUN (sulp, (x, scale),
U x _AND
int scale)
{
U u;
double rv;
int i;
rv = ulp(dval(x));
if (!scale || (i = 2*P + 1 - ((dword0(x) & Exp_mask) >> Exp_shift)) <= 0)
return rv; /* Is there an example where i <= 0 ? */
dword0(u) = Exp_1 + (i << Exp_shift);
#ifndef _DOUBLE_IS_32BITS
dword1(u) = 0;
#endif
return rv * u.d;
}
#endif /*}*/
#ifndef NO_HEX_FP #ifndef NO_HEX_FP
static void static void
@ -221,7 +249,10 @@ _DEFUN (_strtod_r, (ptr, s00, se),
U aadj1, rv, rv0; U aadj1, rv, rv0;
Long L; Long L;
__ULong y, z; __ULong y, z;
_Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; _Bigint *bb = NULL, *bb1, *bd = NULL, *bd0, *bs = NULL, *delta = NULL;
#ifdef Avoid_Underflow
__ULong Lsb, Lsb1;
#endif
#ifdef SET_INEXACT #ifdef SET_INEXACT
int inexact, oldinexact; int inexact, oldinexact;
#endif #endif
@ -279,6 +310,8 @@ _DEFUN (_strtod_r, (ptr, s00, se),
switch((i = gethex(ptr, &s, &fpi1, &exp, &bb, sign)) & STRTOG_Retmask) { switch((i = gethex(ptr, &s, &fpi1, &exp, &bb, sign)) & STRTOG_Retmask) {
case STRTOG_NoNumber: case STRTOG_NoNumber:
s = s00; s = s00;
sign = 0;
/* FALLTHROUGH */
case STRTOG_Zero: case STRTOG_Zero:
break; break;
default: default:
@ -299,14 +332,11 @@ _DEFUN (_strtod_r, (ptr, s00, se),
} }
s0 = s; s0 = s;
y = z = 0; y = z = 0;
for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) { for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
if (nd < DBL_DIG + 1) {
if (nd < 9) if (nd < 9)
y = 10*y + c - '0'; y = 10*y + c - '0';
else else
z = 10*z + c - '0'; z = 10*z + c - '0';
}
}
nd0 = nd; nd0 = nd;
if (strncmp (s, _localeconv_r (ptr)->decimal_point, if (strncmp (s, _localeconv_r (ptr)->decimal_point,
strlen (_localeconv_r (ptr)->decimal_point)) == 0) strlen (_localeconv_r (ptr)->decimal_point)) == 0)
@ -329,20 +359,15 @@ _DEFUN (_strtod_r, (ptr, s00, se),
nz++; nz++;
if (c -= '0') { if (c -= '0') {
nf += nz; nf += nz;
for(i = 1; i < nz; i++) { for(i = 1; i < nz; i++)
if (nd++ <= DBL_DIG + 1) { if (nd++ < 9)
if (nd < 10)
y *= 10; y *= 10;
else else if (nd <= DBL_DIG + 1)
z *= 10; z *= 10;
} if (nd++ < 9)
}
if (nd++ <= DBL_DIG + 1) {
if (nd < 10)
y = 10*y + c; y = 10*y + c;
else else if (nd <= DBL_DIG + 1)
z = 10*z + c; z = 10*z + c;
}
nz = 0; nz = 0;
} }
} }
@ -691,12 +716,20 @@ _DEFUN (_strtod_r, (ptr, s00, se),
/* Put digits into bd: true value = bd * 10^e */ /* Put digits into bd: true value = bd * 10^e */
bd0 = s2b(ptr, s0, nd0, nd, y); bd0 = s2b(ptr, s0, nd0, nd, y);
if (bd0 == NULL)
goto ovfl;
for(;;) { for(;;) {
bd = Balloc(ptr,bd0->_k); bd = Balloc(ptr,bd0->_k);
if (bd == NULL)
goto ovfl;
Bcopy(bd, bd0); Bcopy(bd, bd0);
bb = d2b(ptr,dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */ bb = d2b(ptr,dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */
if (bb == NULL)
goto ovfl;
bs = i2b(ptr,1); bs = i2b(ptr,1);
if (bs == NULL)
goto ovfl;
if (e >= 0) { if (e >= 0) {
bb2 = bb5 = 0; bb2 = bb5 = 0;
@ -716,12 +749,19 @@ _DEFUN (_strtod_r, (ptr, s00, se),
bs2++; bs2++;
#endif #endif
#ifdef Avoid_Underflow #ifdef Avoid_Underflow
Lsb = LSB;
Lsb1 = 0;
j = bbe - scale; j = bbe - scale;
i = j + bbbits - 1; /* logb(rv) */ i = j + bbbits - 1; /* logb(rv) */
if (i < Emin) /* denormal */
j += P - Emin;
else
j = P + 1 - bbbits; j = P + 1 - bbbits;
if (i < Emin) { /* denormal */
i = Emin - i;
j -= i;
if (i < 32)
Lsb <<= i;
else
Lsb1 = Lsb << (i-32);
}
#else /*Avoid_Underflow*/ #else /*Avoid_Underflow*/
#ifdef Sudden_Underflow #ifdef Sudden_Underflow
#ifdef IBM #ifdef IBM
@ -753,19 +793,37 @@ _DEFUN (_strtod_r, (ptr, s00, se),
} }
if (bb5 > 0) { if (bb5 > 0) {
bs = pow5mult(ptr, bs, bb5); bs = pow5mult(ptr, bs, bb5);
if (bs == NULL)
goto ovfl;
bb1 = mult(ptr, bs, bb); bb1 = mult(ptr, bs, bb);
if (bb1 == NULL)
goto ovfl;
Bfree(ptr, bb); Bfree(ptr, bb);
bb = bb1; bb = bb1;
} }
if (bb2 > 0) if (bb2 > 0) {
bb = lshift(ptr, bb, bb2); bb = lshift(ptr, bb, bb2);
if (bd5 > 0) if (bb == NULL)
goto ovfl;
}
if (bd5 > 0) {
bd = pow5mult(ptr, bd, bd5); bd = pow5mult(ptr, bd, bd5);
if (bd2 > 0) if (bd == NULL)
goto ovfl;
}
if (bd2 > 0) {
bd = lshift(ptr, bd, bd2); bd = lshift(ptr, bd, bd2);
if (bs2 > 0) if (bd == NULL)
goto ovfl;
}
if (bs2 > 0) {
bs = lshift(ptr, bs, bs2); bs = lshift(ptr, bs, bs2);
if (bs == NULL)
goto ovfl;
}
delta = diff(ptr, bb, bd); delta = diff(ptr, bb, bd);
if (delta == NULL)
goto ovfl;
dsign = delta->_sign; dsign = delta->_sign;
delta->_sign = 0; delta->_sign = 0;
i = cmp(delta, bs); i = cmp(delta, bs);
@ -852,7 +910,9 @@ _DEFUN (_strtod_r, (ptr, s00, se),
#endif /*Sudden_Underflow*/ #endif /*Sudden_Underflow*/
#endif /*Avoid_Underflow*/ #endif /*Avoid_Underflow*/
adj *= ulp(dval(rv)); adj *= ulp(dval(rv));
if (dsign) if (dsign) {
if (dword0(rv) == Big0 && dword1(rv) == Big1)
goto ovfl;
dval(rv) += adj; dval(rv) += adj;
else else
dval(rv) -= adj; dval(rv) -= adj;
@ -902,6 +962,8 @@ _DEFUN (_strtod_r, (ptr, s00, se),
#endif #endif
0xffffffff)) { 0xffffffff)) {
/*boundary case -- increment exponent*/ /*boundary case -- increment exponent*/
if (dword0(rv) == Big0 && dword1(rv) == Big1)
goto ovfl;
dword0(rv) = (dword0(rv) & Exp_mask) dword0(rv) = (dword0(rv) & Exp_mask)
+ Exp_msk1 + Exp_msk1
#ifdef IBM #ifdef IBM
@ -960,14 +1022,31 @@ _DEFUN (_strtod_r, (ptr, s00, se),
#endif #endif
} }
#ifndef ROUND_BIASED #ifndef ROUND_BIASED
#ifdef Avoid_Underflow
if (Lsb1) {
if (!(dword0(rv) & Lsb1))
break;
}
else if (!(dword1(rv) & Lsb))
break;
#else
if (!(dword1(rv) & LSB)) if (!(dword1(rv) & LSB))
break; break;
#endif
#endif #endif
if (dsign) if (dsign)
#ifdef Avoid_Underflow
dval(rv) += sulp(rv, scale);
#else
dval(rv) += ulp(dval(rv)); dval(rv) += ulp(dval(rv));
#endif
#ifndef ROUND_BIASED #ifndef ROUND_BIASED
else { else {
#ifdef Avoid_Underflow
dval(rv) -= sulp(rv, scale);
#else
dval(rv) -= ulp(dval(rv)); dval(rv) -= ulp(dval(rv));
#endif
#ifndef Sudden_Underflow #ifndef Sudden_Underflow
if (!dval(rv)) if (!dval(rv))
goto undfl; goto undfl;
@ -1044,7 +1123,7 @@ _DEFUN (_strtod_r, (ptr, s00, se),
#ifdef Avoid_Underflow #ifdef Avoid_Underflow
if (scale && y <= 2*P*Exp_msk1) { if (scale && y <= 2*P*Exp_msk1) {
if (aadj <= 0x7fffffff) { if (aadj <= 0x7fffffff) {
if ((z = aadj) <= 0) if ((z = aadj) == 0)
z = 1; z = 1;
aadj = z; aadj = z;
dval(aadj1) = dsign ? aadj : -aadj; dval(aadj1) = dsign ? aadj : -aadj;