mirror of
https://github.com/python/cpython.git
synced 2025-07-27 13:14:41 +00:00
Issue #7632: Fix a serious wrong output bug for string -> float conversion.
Also remove some now unused variables, and add comments clarifying the possible outputs of the parsing section of _Py_dg_strtod. Thanks Eric Smith for reviewing.
This commit is contained in:
parent
ed44dfa4c7
commit
476279f18b
3 changed files with 49 additions and 19 deletions
|
@ -1340,7 +1340,7 @@ bigcomp(U *rv, const char *s0, BCinfo *bc)
|
|||
double
|
||||
_Py_dg_strtod(const char *s00, char **se)
|
||||
{
|
||||
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dp0, dp1, dplen, e, e1, error;
|
||||
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1, error;
|
||||
int esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
|
||||
const char *s, *s0, *s1;
|
||||
double aadj, aadj1;
|
||||
|
@ -1349,7 +1349,7 @@ _Py_dg_strtod(const char *s00, char **se)
|
|||
BCinfo bc;
|
||||
Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
|
||||
|
||||
sign = nz0 = nz = dplen = 0;
|
||||
sign = nz0 = nz = 0;
|
||||
dval(&rv) = 0.;
|
||||
for(s = s00;;s++) switch(*s) {
|
||||
case '-':
|
||||
|
@ -1388,11 +1388,8 @@ _Py_dg_strtod(const char *s00, char **se)
|
|||
else if (nd < 16)
|
||||
z = 10*z + c - '0';
|
||||
nd0 = nd;
|
||||
dp0 = dp1 = s - s0;
|
||||
if (c == '.') {
|
||||
c = *++s;
|
||||
dp1 = s - s0;
|
||||
dplen = 1;
|
||||
if (!nd) {
|
||||
for(; c == '0'; c = *++s)
|
||||
nz++;
|
||||
|
@ -1477,6 +1474,32 @@ _Py_dg_strtod(const char *s00, char **se)
|
|||
|
||||
if (!nd0)
|
||||
nd0 = nd;
|
||||
|
||||
/* Summary of parsing results. The parsing stage gives values
|
||||
* s0, nd0, nd, e, y and z such that:
|
||||
*
|
||||
* - nd >= nd0 >= 1
|
||||
*
|
||||
* - the nd significant digits are in s0[0:nd0] and s0[nd0+1:nd+1]
|
||||
* (using the usual Python half-open slice notation)
|
||||
*
|
||||
* - the absolute value of the number represented by the original input
|
||||
* string is n * 10**e, where n is the integer represented by the
|
||||
* concatenation of s0[0:nd0] and s0[nd0+1:nd+1]
|
||||
*
|
||||
* - the first significant digit is nonzero
|
||||
*
|
||||
* - the last significant digit may or may not be nonzero; (some code
|
||||
* currently assumes that it's nonzero; this is a bug)
|
||||
*
|
||||
* - y contains the value represented by the first min(9, nd)
|
||||
* significant digits
|
||||
*
|
||||
* - if nd > 9, z contains the value represented by significant digits
|
||||
* with indices in [9, min(16, nd)). So y * 10**(min(16, nd) - 9) + z
|
||||
* gives the value represented by the first min(16, nd) sig. digits.
|
||||
*/
|
||||
|
||||
k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
|
||||
dval(&rv) = y;
|
||||
if (k > 9) {
|
||||
|
@ -1593,15 +1616,18 @@ _Py_dg_strtod(const char *s00, char **se)
|
|||
/* ASSERT(STRTOD_DIGLIM >= 18); 18 == one more than the */
|
||||
/* minimum number of decimal digits to distinguish double values */
|
||||
/* in IEEE arithmetic. */
|
||||
i = j = 18;
|
||||
if (i > nd0)
|
||||
j += dplen;
|
||||
for(;;) {
|
||||
if (--j <= dp1 && j >= dp0)
|
||||
j = dp0 - 1;
|
||||
if (s0[j] != '0')
|
||||
break;
|
||||
|
||||
/* Truncate input to 18 significant digits, then discard any trailing
|
||||
zeros on the result by updating nd, nd0, e and y suitably. (There's
|
||||
no need to update z; it's not reused beyond this point.) */
|
||||
for (i = 18; i > 0; ) {
|
||||
/* scan back until we hit a nonzero digit. significant digit 'i'
|
||||
is s0[i] if i < nd0, s0[i+1] if i >= nd0. */
|
||||
--i;
|
||||
if (s0[i < nd0 ? i : i+1] != '0') {
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
e += nd - i;
|
||||
nd = i;
|
||||
|
@ -1611,8 +1637,8 @@ _Py_dg_strtod(const char *s00, char **se)
|
|||
y = 0;
|
||||
for(i = 0; i < nd0; ++i)
|
||||
y = 10*y + s0[i] - '0';
|
||||
for(j = dp1; i < nd; ++i)
|
||||
y = 10*y + s0[j++] - '0';
|
||||
for(; i < nd; ++i)
|
||||
y = 10*y + s0[i+1] - '0';
|
||||
}
|
||||
}
|
||||
bd0 = s2b(s0, nd0, nd, y);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue