FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

Issue #7632: Fix a serious wrong output bug for string -> float conve… · python-emscripten/cpython@476279f · GitHub

Repository navigation

Commit 476279f

Browse files
committed
Issue python#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.
1 parent ed44dfa commit 476279f

3 files changed

Lines changed: 49 additions & 19 deletions

File tree

‎Lib/test/test_strtod.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ def test_particular(self):
258258
# issue 7632 bug 5: the following 2 strings convert differently
259259
'1000000000000000000000000000000000000000e-16',
260260
#'10000000000000000000000000000000000000000e-17',
261+
# issue 7632 bug 8: the following produced 10.0
262+
'10.900000000000000012345678912345678912345',
261263
]
262264
for s in test_strings:
263265
self.check_strtod(s)

‎Misc/NEWS‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ Core and Builtins
1616
methods of bytes, bytearray and unicode objects by using a common
1717
implementation based on stringlib's fast search. Patch by Florent Xicluna.
1818

19-
- Issue #7632: Fix a crash in dtoa.c that occurred in debug builds
20-
when parsing certain long numeric strings corresponding to subnormal
21-
values. Also fix a number of bugs in dtoa.c that could lead to
22-
incorrectly rounded results when converting strings to floats.
19+
- Issue #7632: Fix various str -> float conversion bugs present in 2.7
20+
alpha 2, including: (1) a serious 'wrong output' bug that could
21+
occur for long (> 40 digit) input strings, (2) a crash in dtoa.c
22+
that occurred in debug builds when parsing certain long numeric
23+
strings corresponding to subnormal values, and (3) a number of flaws
24+
that could lead to incorrectly rounded results.
2325

2426
- Issue #7319, #7770: Silence DeprecationWarning by default when -3 is not
2527
used.

‎Python/dtoa.c‎

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1340,7 +1340,7 @@ bigcomp(U *rv, const char *s0, BCinfo *bc)
13401340
double
13411341
_Py_dg_strtod(const char *s00, char **se)
13421342
{
1343-
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dp0, dp1, dplen, e, e1, error;
1343+
int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, e, e1, error;
13441344
int esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
13451345
const char *s, *s0, *s1;
13461346
double aadj, aadj1;
@@ -1349,7 +1349,7 @@ _Py_dg_strtod(const char *s00, char **se)
13491349
BCinfo bc;
13501350
Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
13511351

1352-
sign = nz0 = nz = dplen = 0;
1352+
sign = nz0 = nz = 0;
13531353
dval(&rv) = 0.;
13541354
for(s = s00;;s++) switch(*s) {
13551355
case '-':
@@ -1388,11 +1388,8 @@ _Py_dg_strtod(const char *s00, char **se)
13881388
else if (nd < 16)
13891389
z = 10*z + c - '0';
13901390
nd0 = nd;
1391-
dp0 = dp1 = s - s0;
13921391
if (c == '.') {
13931392
c = *++s;
1394-
dp1 = s - s0;
1395-
dplen = 1;
13961393
if (!nd) {
13971394
for(; c == '0'; c = *++s)
13981395
nz++;
@@ -1477,6 +1474,32 @@ _Py_dg_strtod(const char *s00, char **se)
14771474

14781475
if (!nd0)
14791476
nd0 = nd;
1477+
1478+
/* Summary of parsing results. The parsing stage gives values
1479+
* s0, nd0, nd, e, y and z such that:
1480+
*
1481+
* - nd >= nd0 >= 1
1482+
*
1483+
* - the nd significant digits are in s0[0:nd0] and s0[nd0+1:nd+1]
1484+
* (using the usual Python half-open slice notation)
1485+
*
1486+
* - the absolute value of the number represented by the original input
1487+
* string is n * 10**e, where n is the integer represented by the
1488+
* concatenation of s0[0:nd0] and s0[nd0+1:nd+1]
1489+
*
1490+
* - the first significant digit is nonzero
1491+
*
1492+
* - the last significant digit may or may not be nonzero; (some code
1493+
* currently assumes that it's nonzero; this is a bug)
1494+
*
1495+
* - y contains the value represented by the first min(9, nd)
1496+
* significant digits
1497+
*
1498+
* - if nd > 9, z contains the value represented by significant digits
1499+
* with indices in [9, min(16, nd)). So y * 10**(min(16, nd) - 9) + z
1500+
* gives the value represented by the first min(16, nd) sig. digits.
1501+
*/
1502+
14801503
k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
14811504
dval(&rv) = y;
14821505
if (k > 9) {
@@ -1593,15 +1616,18 @@ _Py_dg_strtod(const char *s00, char **se)
15931616
/* ASSERT(STRTOD_DIGLIM >= 18); 18 == one more than the */
15941617
/* minimum number of decimal digits to distinguish double values */
15951618
/* in IEEE arithmetic. */
1596-
i = j = 18;
1597-
if (i > nd0)
1598-
j += dplen;
1599-
for(;;) {
1600-
if (--j <= dp1 && j >= dp0)
1601-
j = dp0 - 1;
1602-
if (s0[j] != '0')
1603-
break;
1619+
1620+
/* Truncate input to 18 significant digits, then discard any trailing
1621+
zeros on the result by updating nd, nd0, e and y suitably. (There's
1622+
no need to update z; it's not reused beyond this point.) */
1623+
for (i = 18; i > 0; ) {
1624+
/* scan back until we hit a nonzero digit. significant digit 'i'
1625+
is s0[i] if i < nd0, s0[i+1] if i >= nd0. */
16041626
--i;
1627+
if (s0[i < nd0 ? i : i+1] != '0') {
1628+
++i;
1629+
break;
1630+
}
16051631
}
16061632
e += nd - i;
16071633
nd = i;
@@ -1611,8 +1637,8 @@ _Py_dg_strtod(const char *s00, char **se)
16111637
y = 0;
16121638
for(i = 0; i < nd0; ++i)
16131639
y = 10*y + s0[i] - '0';
1614-
for(j = dp1; i < nd; ++i)
1615-
y = 10*y + s0[j++] - '0';
1640+
for(; i < nd; ++i)
1641+
y = 10*y + s0[i+1] - '0';
16161642
}
16171643
}
16181644
bd0 = s2b(s0, nd0, nd, y);

0 commit comments

Comments
 (0)

Back | FazBrowse Home | New Git URL