| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 747e8b3 commit 45b6365
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -123,10 +123,6 @@ def test_halfway_cases(self): | |||
| 123 | 123 | digits = m * 5**-e | |
| 124 | 124 | exponent = e | |
| 125 | 125 | s = '{}e{}'.format(digits, exponent) | |
| 126 | - | ||
| 127 | - # for the moment, ignore errors from trailing zeros | ||
| 128 | - if digits % 10 == 0: | ||
| 129 | - continue | ||
| 130 | 126 | self.check_strtod(s) | |
| 131 | 127 | ||
| 132 | 128 | # get expected answer via struct, to triple check | |
@@ -175,7 +171,8 @@ def test_bigcomp(self): | |||
| 175 | 171 | self.check_strtod(s) | |
| 176 | 172 | ||
| 177 | 173 | def test_parsing(self): | |
| 178 | - digits = tuple(map(str, range(10))) | ||
| 174 | + # make '0' more likely to be chosen than other digits | ||
| 175 | + digits = '000000123456789' | ||
| 179 | 176 | signs = ('+', '-', '') | |
| 180 | 177 | ||
| 181 | 178 | # put together random short valid strings | |
@@ -257,7 +254,9 @@ def test_particular(self): | |||
| 257 | 254 | '247032822920623295e-341', | |
| 258 | 255 | # issue 7632 bug 5: the following 2 strings convert differently | |
| 259 | 256 | '1000000000000000000000000000000000000000e-16', | |
| 260 | - #'10000000000000000000000000000000000000000e-17', | ||
| 257 | + '10000000000000000000000000000000000000000e-17', | ||
| 258 | + # issue 7632 bug 8: the following produced 10.0 | ||
| 259 | + '10.900000000000000012345678912345678912345', | ||
| 261 | 260 | ] | |
| 262 | 261 | for s in test_strings: | |
| 263 | 262 | self.check_strtod(s) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -16,10 +16,12 @@ Core and Builtins | |||
| 16 | 16 | methods of bytes, bytearray and unicode objects by using a common | |
| 17 | 17 | implementation based on stringlib's fast search. Patch by Florent Xicluna. | |
| 18 | 18 | ||
| 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. | ||
| 23 | 25 | ||
| 24 | 26 | - The __complex__ method is now looked up on the class of instances to make it | |
| 25 | 27 | consistent with other special methods. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1340,16 +1340,17 @@ bigcomp(U *rv, const char *s0, BCinfo *bc) | |||
| 1340 | 1340 | double | |
| 1341 | 1341 | _Py_dg_strtod(const char *s00, char **se) | |
| 1342 | 1342 | { | |
| 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; | ||
| 1344 | 1344 | int esign, i, j, k, nd, nd0, nf, nz, nz0, sign; | |
| 1345 | 1345 | const char *s, *s0, *s1; | |
| 1346 | 1346 | double aadj, aadj1; | |
| 1347 | 1347 | U aadj2, adj, rv, rv0; | |
| 1348 | - ULong y, z, L; | ||
| 1348 | + ULong y, z, abse; | ||
| 1349 | + Long L; | ||
| 1349 | 1350 | BCinfo bc; | |
| 1350 | 1351 | Bigint *bb, *bb1, *bd, *bd0, *bs, *delta; | |
| 1351 | 1352 | ||
| 1352 | - sign = nz0 = nz = dplen = 0; | ||
| 1353 | + sign = nz0 = nz = 0; | ||
| 1353 | 1354 | dval(&rv) = 0.; | |
| 1354 | 1355 | for(s = s00;;s++) switch(*s) { | |
| 1355 | 1356 | case '-': | |
@@ -1381,18 +1382,11 @@ _Py_dg_strtod(const char *s00, char **se) | |||
| 1381 | 1382 | goto ret; | |
| 1382 | 1383 | } | |
| 1383 | 1384 | s0 = s; | |
| 1384 | - y = z = 0; | ||
| 1385 | 1385 | for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++) | |
| 1386 | - if (nd < 9) | ||
| 1387 | - y = 10*y + c - '0'; | ||
| 1388 | - else if (nd < 16) | ||
| 1389 | - z = 10*z + c - '0'; | ||
| 1386 | + ; | ||
| 1390 | 1387 | nd0 = nd; | |
| 1391 | - dp0 = dp1 = s - s0; | ||
| 1392 | 1388 | if (c == '.') { | |
| 1393 | 1389 | c = *++s; | |
| 1394 | - dp1 = s - s0; | ||
| 1395 | - dplen = 1; | ||
| 1396 | 1390 | if (!nd) { | |
| 1397 | 1391 | for(; c == '0'; c = *++s) | |
| 1398 | 1392 | nz++; | |
@@ -1409,15 +1403,7 @@ _Py_dg_strtod(const char *s00, char **se) | |||
| 1409 | 1403 | nz++; | |
| 1410 | 1404 | if (c -= '0') { | |
| 1411 | 1405 | nf += nz; | |
| 1412 | - for(i = 1; i < nz; i++) | ||
| 1413 | - if (nd++ < 9) | ||
| 1414 | - y *= 10; | ||
| 1415 | - else if (nd <= DBL_DIG + 1) | ||
| 1416 | - z *= 10; | ||
| 1417 | - if (nd++ < 9) | ||
| 1418 | - y = 10*y + c; | ||
| 1419 | - else if (nd <= DBL_DIG + 1) | ||
| 1420 | - z = 10*z + c; | ||
| 1406 | + nd += nz; | ||
| 1421 | 1407 | nz = 0; | |
| 1422 | 1408 | } | |
| 1423 | 1409 | } | |
@@ -1440,17 +1426,17 @@ _Py_dg_strtod(const char *s00, char **se) | |||
| 1440 | 1426 | while(c == '0') | |
| 1441 | 1427 | c = *++s; | |
| 1442 | 1428 | if (c > '0' && c <= '9') { | |
| 1443 | - L = c - '0'; | ||
| 1429 | + abse = c - '0'; | ||
| 1444 | 1430 | s1 = s; | |
| 1445 | 1431 | while((c = *++s) >= '0' && c <= '9') | |
| 1446 | - L = 10*L + c - '0'; | ||
| 1447 | - if (s - s1 > 8 || L > MAX_ABS_EXP) | ||
| 1432 | + abse = 10*abse + c - '0'; | ||
| 1433 | + if (s - s1 > 8 || abse > MAX_ABS_EXP) | ||
| 1448 | 1434 | /* Avoid confusion from exponents | |
| 1449 | 1435 | * so large that e might overflow. | |
| 1450 | 1436 | */ | |
| 1451 | 1437 | e = (int)MAX_ABS_EXP; /* safe for 16 bit ints */ | |
| 1452 | 1438 | else | |
| 1453 | - e = (int)L; | ||
| 1439 | + e = (int)abse; | ||
| 1454 | 1440 | if (esign) | |
| 1455 | 1441 | e = -e; | |
| 1456 | 1442 | } | |
@@ -1468,15 +1454,78 @@ _Py_dg_strtod(const char *s00, char **se) | |||
| 1468 | 1454 | } | |
| 1469 | 1455 | goto ret; | |
| 1470 | 1456 | } | |
| 1471 | - bc.e0 = e1 = e -= nf; | ||
| 1457 | + e -= nf; | ||
| 1458 | + if (!nd0) | ||
| 1459 | + nd0 = nd; | ||
| 1460 | + | ||
| 1461 | + /* strip trailing zeros */ | ||
| 1462 | + for (i = nd; i > 0; ) { | ||
| 1463 | + /* scan back until we hit a nonzero digit. significant digit 'i' | ||
| 1464 | + is s0[i] if i < nd0, s0[i+1] if i >= nd0. */ | ||
| 1465 | + --i; | ||
| 1466 | + if (s0[i < nd0 ? i : i+1] != '0') { | ||
| 1467 | + ++i; | ||
| 1468 | + break; | ||
| 1469 | + } | ||
| 1470 | + } | ||
| 1471 | + e += nd - i; | ||
| 1472 | + nd = i; | ||
| 1473 | + if (nd0 > nd) | ||
| 1474 | + nd0 = nd; | ||
| 1472 | 1475 | ||
| 1473 | 1476 | /* Now we have nd0 digits, starting at s0, followed by a | |
| 1474 | 1477 | * decimal point, followed by nd-nd0 digits. The number we're | |
| 1475 | 1478 | * after is the integer represented by those digits times | |
| 1476 | 1479 | * 10**e */ | |
| 1477 | 1480 | ||
| 1478 | - if (!nd0) | ||
| 1479 | - nd0 = nd; | ||
| 1481 | + bc.e0 = e1 = e; | ||
| 1482 | + | ||
| 1483 | + /* Summary of parsing results. The parsing stage gives values | ||
| 1484 | + * s0, nd0, nd, e, sign, where: | ||
| 1485 | + * | ||
| 1486 | + * - s0 points to the first significant digit of the input string s00; | ||
| 1487 | + * | ||
| 1488 | + * - nd is the total number of significant digits (here, and | ||
| 1489 | + * below, 'significant digits' means the set of digits of the | ||
| 1490 | + * significand of the input that remain after ignoring leading | ||
| 1491 | + * and trailing zeros. | ||
| 1492 | + * | ||
| 1493 | + * - nd0 indicates the position of the decimal point (if | ||
| 1494 | + * present): so the nd significant digits are in s0[0:nd0] and | ||
| 1495 | + * s0[nd0+1:nd+1] using the usual Python half-open slice | ||
| 1496 | + * notation. (If nd0 < nd, then s0[nd0] necessarily contains | ||
| 1497 | + * a '.' character; if nd0 == nd, then it could be anything.) | ||
| 1498 | + * | ||
| 1499 | + * - e is the adjusted exponent: the absolute value of the number | ||
| 1500 | + * represented by the original input string is n * 10**e, where | ||
| 1501 | + * n is the integer represented by the concatenation of | ||
| 1502 | + * s0[0:nd0] and s0[nd0+1:nd+1] | ||
| 1503 | + * | ||
| 1504 | + * - sign gives the sign of the input: 1 for negative, 0 for positive | ||
| 1505 | + * | ||
| 1506 | + * - the first and last significant digits are nonzero | ||
| 1507 | + */ | ||
| 1508 | + | ||
| 1509 | + /* put first DBL_DIG+1 digits into integer y and z. | ||
| 1510 | + * | ||
| 1511 | + * - y contains the value represented by the first min(9, nd) | ||
| 1512 | + * significant digits | ||
| 1513 | + * | ||
| 1514 | + * - if nd > 9, z contains the value represented by significant digits | ||
| 1515 | + * with indices in [9, min(16, nd)). So y * 10**(min(16, nd) - 9) + z | ||
| 1516 | + * gives the value represented by the first min(16, nd) sig. digits. | ||
| 1517 | + */ | ||
| 1518 | + | ||
| 1519 | + y = z = 0; | ||
| 1520 | + for (i = 0; i < nd; i++) { | ||
| 1521 | + if (i < 9) | ||
| 1522 | + y = 10*y + s0[i < nd0 ? i : i+1] - '0'; | ||
| 1523 | + else if (i < DBL_DIG+1) | ||
| 1524 | + z = 10*z + s0[i < nd0 ? i : i+1] - '0'; | ||
| 1525 | + else | ||
| 1526 | + break; | ||
| 1527 | + } | ||
| 1528 | + | ||
| 1480 | 1529 | k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1; | |
| 1481 | 1530 | dval(&rv) = y; | |
| 1482 | 1531 | if (k > 9) { | |
@@ -1593,15 +1642,18 @@ _Py_dg_strtod(const char *s00, char **se) | |||
| 1593 | 1642 | /* ASSERT(STRTOD_DIGLIM >= 18); 18 == one more than the */ | |
| 1594 | 1643 | /* minimum number of decimal digits to distinguish double values */ | |
| 1595 | 1644 | /* 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; | ||
| 1645 | + | ||
| 1646 | + /* Truncate input to 18 significant digits, then discard any trailing | ||
| 1647 | + zeros on the result by updating nd, nd0, e and y suitably. (There's | ||
| 1648 | + no need to update z; it's not reused beyond this point.) */ | ||
| 1649 | + for (i = 18; i > 0; ) { | ||
| 1650 | + /* scan back until we hit a nonzero digit. significant digit 'i' | ||
| 1651 | + is s0[i] if i < nd0, s0[i+1] if i >= nd0. */ | ||
| 1604 | 1652 | --i; | |
| 1653 | + if (s0[i < nd0 ? i : i+1] != '0') { | ||
| 1654 | + ++i; | ||
| 1655 | + break; | ||
| 1656 | + } | ||
| 1605 | 1657 | } | |
| 1606 | 1658 | e += nd - i; | |
| 1607 | 1659 | nd = i; | |
@@ -1611,8 +1663,8 @@ _Py_dg_strtod(const char *s00, char **se) | |||
| 1611 | 1663 | y = 0; | |
| 1612 | 1664 | for(i = 0; i < nd0; ++i) | |
| 1613 | 1665 | y = 10*y + s0[i] - '0'; | |
| 1614 | - for(j = dp1; i < nd; ++i) | ||
| 1615 | - y = 10*y + s0[j++] - '0'; | ||
| 1666 | + for(; i < nd; ++i) | ||
| 1667 | + y = 10*y + s0[i+1] - '0'; | ||
| 1616 | 1668 | } | |
| 1617 | 1669 | } | |
| 1618 | 1670 | bd0 = s2b(s0, nd0, nd, y); | |
| Back | FazBrowse Home | New Git URL |
0 commit comments