More dtoa.c cleanup; remove the need for bc.dplen, bc.dp0 and bc.dp1.

This commit is contained in:
Mark Dickinson 2010-01-13 22:20:10 +00:00
parent 02139d74ba
commit d2a9940acb
1 changed files with 47 additions and 73 deletions

View File

@ -270,7 +270,7 @@ typedef union { double d; ULong L[2]; } U;
typedef struct BCinfo BCinfo; typedef struct BCinfo BCinfo;
struct struct
BCinfo { BCinfo {
int dp0, dp1, dplen, dsign, e0, nd, nd0, scale; int dsign, e0, nd, nd0, scale;
}; };
#define FFFFFFFF 0xffffffffUL #define FFFFFFFF 0xffffffffUL
@ -437,7 +437,7 @@ multadd(Bigint *b, int m, int a) /* multiply by m and add a */
NULL on failure. */ NULL on failure. */
static Bigint * static Bigint *
s2b(const char *s, int nd0, int nd, ULong y9, int dplen) s2b(const char *s, int nd0, int nd, ULong y9)
{ {
Bigint *b; Bigint *b;
int i, k; int i, k;
@ -451,18 +451,16 @@ s2b(const char *s, int nd0, int nd, ULong y9, int dplen)
b->x[0] = y9; b->x[0] = y9;
b->wds = 1; b->wds = 1;
i = 9; if (nd <= 9)
if (9 < nd0) { return b;
s += 9; s += 9;
do { for (i = 9; i < nd0; i++) {
b = multadd(b, 10, *s++ - '0'); b = multadd(b, 10, *s++ - '0');
if (b == NULL) if (b == NULL)
return NULL; return NULL;
} while(++i < nd0);
s += dplen;
} }
else s++;
s += dplen + 9;
for(; i < nd; i++) { for(; i < nd; i++) {
b = multadd(b, 10, *s++ - '0'); b = multadd(b, 10, *s++ - '0');
if (b == NULL) if (b == NULL)
@ -1180,26 +1178,14 @@ sulp(U *x, BCinfo *bc)
bc is a struct containing information gathered during the parsing and bc is a struct containing information gathered during the parsing and
estimation steps of _Py_dg_strtod. Description of fields follows: estimation steps of _Py_dg_strtod. Description of fields follows:
bc->dp0 gives the position of the decimal point in the input string
(if any), relative to the start of s0. If there's no decimal
point, it points to one past the last significant digit.
bc->dp1 gives the position immediately following the decimal point in
the input string, relative to the start of s0. If there's no
decimal point, it points to one past the last significant digit.
bc->dplen gives the length of the decimal separator. In the current
implementation, which only allows '.' as a decimal separator, it's
1 if a separator is present in the significant digits of s0, and 0
otherwise.
bc->dsign is 1 if rv < decimal value, 0 if rv >= decimal value. In bc->dsign is 1 if rv < decimal value, 0 if rv >= decimal value. In
normal use, it should almost always be 1 when bigcomp is entered. normal use, it should almost always be 1 when bigcomp is entered.
bc->e0 gives the exponent of the input value, such that dv = (integer bc->e0 gives the exponent of the input value, such that dv = (integer
given by the bd->nd digits of s0) * 10**e0 given by the bd->nd digits of s0) * 10**e0
bc->nd gives the total number of significant digits of s0. bc->nd gives the total number of significant digits of s0. It will
be at least 1.
bc->nd0 gives the number of significant digits of s0 before the bc->nd0 gives the number of significant digits of s0 before the
decimal separator. If there's no decimal separator, bc->nd0 == decimal separator. If there's no decimal separator, bc->nd0 ==
@ -1218,13 +1204,14 @@ static int
bigcomp(U *rv, const char *s0, BCinfo *bc) bigcomp(U *rv, const char *s0, BCinfo *bc)
{ {
Bigint *b, *d; Bigint *b, *d;
int b2, bbits, d2, dd, dig, i, j, nd, nd0, p2, p5; int b2, bbits, d2, dd, i, nd, nd0, p2, p5;
dd = 0; /* silence compiler warning about possibly unused variable */
nd = bc->nd; nd = bc->nd;
nd0 = bc->nd0; nd0 = bc->nd0;
p5 = nd + bc->e0; p5 = nd + bc->e0;
if (rv->d == 0.) { /* special case: value near underflow-to-zero */ if (rv->d == 0.) {
/* threshold was rounded to zero */ /* special case because d2b doesn't handle 0.0 */
b = i2b(0); b = i2b(0);
if (b == NULL) if (b == NULL)
return -1; return -1;
@ -1243,9 +1230,8 @@ bigcomp(U *rv, const char *s0, BCinfo *bc)
that b << i has at most P significant bits and p2 - i >= Emin - P + that b << i has at most P significant bits and p2 - i >= Emin - P +
1. */ 1. */
i = P - bbits; i = P - bbits;
j = p2 - (Emin - P + 1); if (i > p2 - (Emin - P + 1))
if (i > j) i = p2 - (Emin - P + 1);
i = j;
/* increment i so that we shift b by an extra bit; then or-ing a 1 into /* increment i so that we shift b by an extra bit; then or-ing a 1 into
the lsb of b gives us rv/2^(bc->scale) + 0.5ulp. */ the lsb of b gives us rv/2^(bc->scale) + 0.5ulp. */
b = lshift(b, ++i); b = lshift(b, ++i);
@ -1300,55 +1286,43 @@ bigcomp(U *rv, const char *s0, BCinfo *bc)
} }
} }
/* Now 10*b/d = exactly half-way between the two floating-point values /* if b >= d, round down */
on either side of the input string. If b >= d, round down. */
if (cmp(b, d) >= 0) { if (cmp(b, d) >= 0) {
dd = -1; dd = -1;
goto ret; goto ret;
} }
/* Compute first digit of 10*b/d. */
b = multadd(b, 10, 0);
if (b == NULL) {
Bfree(d);
return -1;
}
dig = quorem(b, d);
assert(dig < 10);
/* Compare b/d with s0 */ /* Compare b/d with s0 */
for(i = 0; i < nd0; i++) {
assert(nd > 0); b = multadd(b, 10, 0);
dd = 9999; /* silence gcc compiler warning */ if (b == NULL) {
for(i = 0; i < nd0; ) { Bfree(d);
if ((dd = s0[i++] - '0' - dig)) return -1;
}
dd = *s0++ - '0' - quorem(b, d);
if (dd)
goto ret; goto ret;
if (!b->x[0] && b->wds == 1) { if (!b->x[0] && b->wds == 1) {
if (i < nd) if (i < nd)
dd = 1; dd = 1;
goto ret; goto ret;
} }
}
s0++;
for(; i < nd; i++) {
b = multadd(b, 10, 0); b = multadd(b, 10, 0);
if (b == NULL) { if (b == NULL) {
Bfree(d); Bfree(d);
return -1; return -1;
} }
dig = quorem(b,d); dd = *s0++ - '0' - quorem(b, d);
} if (dd)
for(j = bc->dp1; i++ < nd;) {
if ((dd = s0[j++] - '0' - dig))
goto ret; goto ret;
if (!b->x[0] && b->wds == 1) { if (!b->x[0] && b->wds == 1) {
if (i < nd) if (i < nd)
dd = 1; dd = 1;
goto ret; goto ret;
} }
b = multadd(b, 10, 0);
if (b == NULL) {
Bfree(d);
return -1;
}
dig = quorem(b,d);
} }
if (b->x[0] || b->wds > 1) if (b->x[0] || b->wds > 1)
dd = -1; dd = -1;
@ -1369,7 +1343,7 @@ bigcomp(U *rv, const char *s0, BCinfo *bc)
double double
_Py_dg_strtod(const char *s00, char **se) _Py_dg_strtod(const char *s00, char **se)
{ {
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1, error; int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dp0, dp1, dplen, e, e1, error;
int esign, i, j, k, nd, nd0, nf, nz, nz0, sign; int esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
const char *s, *s0, *s1; const char *s, *s0, *s1;
double aadj, aadj1; double aadj, aadj1;
@ -1378,7 +1352,7 @@ _Py_dg_strtod(const char *s00, char **se)
BCinfo bc; BCinfo bc;
Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
sign = nz0 = nz = bc.dplen = 0; sign = nz0 = nz = dplen = 0;
dval(&rv) = 0.; dval(&rv) = 0.;
for(s = s00;;s++) switch(*s) { for(s = s00;;s++) switch(*s) {
case '-': case '-':
@ -1417,11 +1391,11 @@ _Py_dg_strtod(const char *s00, char **se)
else if (nd < 16) else if (nd < 16)
z = 10*z + c - '0'; z = 10*z + c - '0';
nd0 = nd; nd0 = nd;
bc.dp0 = bc.dp1 = s - s0; dp0 = dp1 = s - s0;
if (c == '.') { if (c == '.') {
c = *++s; c = *++s;
bc.dp1 = s - s0; dp1 = s - s0;
bc.dplen = bc.dp1 - bc.dp0; dplen = 1;
if (!nd) { if (!nd) {
for(; c == '0'; c = *++s) for(; c == '0'; c = *++s)
nz++; nz++;
@ -1624,10 +1598,10 @@ _Py_dg_strtod(const char *s00, char **se)
/* in IEEE arithmetic. */ /* in IEEE arithmetic. */
i = j = 18; i = j = 18;
if (i > nd0) if (i > nd0)
j += bc.dplen; j += dplen;
for(;;) { for(;;) {
if (--j <= bc.dp1 && j >= bc.dp0) if (--j <= dp1 && j >= dp0)
j = bc.dp0 - 1; j = dp0 - 1;
if (s0[j] != '0') if (s0[j] != '0')
break; break;
--i; --i;
@ -1640,11 +1614,11 @@ _Py_dg_strtod(const char *s00, char **se)
y = 0; y = 0;
for(i = 0; i < nd0; ++i) for(i = 0; i < nd0; ++i)
y = 10*y + s0[i] - '0'; y = 10*y + s0[i] - '0';
for(j = bc.dp1; i < nd; ++i) for(j = dp1; i < nd; ++i)
y = 10*y + s0[j++] - '0'; y = 10*y + s0[j++] - '0';
} }
} }
bd0 = s2b(s0, nd0, nd, y, bc.dplen); bd0 = s2b(s0, nd0, nd, y);
if (bd0 == NULL) if (bd0 == NULL)
goto failed_malloc; goto failed_malloc;