mirror of https://github.com/python/cpython
Issue #7632: Fix one more case of incorrect rounding for str -> float
conversion (see bug 5 in the issue tracker).
This commit is contained in:
parent
db983a7c38
commit
811ff822f8
|
@ -123,10 +123,6 @@ class StrtodTests(unittest.TestCase):
|
|||
digits = m * 5**-e
|
||||
exponent = e
|
||||
s = '{}e{}'.format(digits, exponent)
|
||||
|
||||
# for the moment, ignore errors from trailing zeros
|
||||
if digits % 10 == 0:
|
||||
continue
|
||||
self.check_strtod(s)
|
||||
|
||||
# get expected answer via struct, to triple check
|
||||
|
@ -175,7 +171,8 @@ class StrtodTests(unittest.TestCase):
|
|||
self.check_strtod(s)
|
||||
|
||||
def test_parsing(self):
|
||||
digits = tuple(map(str, xrange(10)))
|
||||
# make '0' more likely to be chosen than other digits
|
||||
digits = '000000123456789'
|
||||
signs = ('+', '-', '')
|
||||
|
||||
# put together random short valid strings
|
||||
|
@ -257,7 +254,7 @@ class StrtodTests(unittest.TestCase):
|
|||
'247032822920623295e-341',
|
||||
# issue 7632 bug 5: the following 2 strings convert differently
|
||||
'1000000000000000000000000000000000000000e-16',
|
||||
#'10000000000000000000000000000000000000000e-17',
|
||||
'10000000000000000000000000000000000000000e-17',
|
||||
# issue 7632 bug 8: the following produced 10.0
|
||||
'10.900000000000000012345678912345678912345',
|
||||
]
|
||||
|
|
|
@ -1381,12 +1381,8 @@ _Py_dg_strtod(const char *s00, char **se)
|
|||
goto ret;
|
||||
}
|
||||
s0 = s;
|
||||
y = z = 0;
|
||||
for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
|
||||
if (nd < 9)
|
||||
y = 10*y + c - '0';
|
||||
else if (nd < 16)
|
||||
z = 10*z + c - '0';
|
||||
;
|
||||
nd0 = nd;
|
||||
if (c == '.') {
|
||||
c = *++s;
|
||||
|
@ -1406,15 +1402,7 @@ _Py_dg_strtod(const char *s00, char **se)
|
|||
nz++;
|
||||
if (c -= '0') {
|
||||
nf += nz;
|
||||
for(i = 1; i < nz; i++)
|
||||
if (nd++ < 9)
|
||||
y *= 10;
|
||||
else if (nd <= DBL_DIG + 1)
|
||||
z *= 10;
|
||||
if (nd++ < 9)
|
||||
y = 10*y + c;
|
||||
else if (nd <= DBL_DIG + 1)
|
||||
z = 10*z + c;
|
||||
nd += nz;
|
||||
nz = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1465,32 +1453,59 @@ _Py_dg_strtod(const char *s00, char **se)
|
|||
}
|
||||
goto ret;
|
||||
}
|
||||
bc.e0 = e1 = e -= nf;
|
||||
e -= nf;
|
||||
if (!nd0)
|
||||
nd0 = nd;
|
||||
|
||||
/* strip trailing zeros */
|
||||
for (i = nd; 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;
|
||||
if (nd0 > nd)
|
||||
nd0 = nd;
|
||||
|
||||
/* Now we have nd0 digits, starting at s0, followed by a
|
||||
* decimal point, followed by nd-nd0 digits. The number we're
|
||||
* after is the integer represented by those digits times
|
||||
* 10**e */
|
||||
|
||||
if (!nd0)
|
||||
nd0 = nd;
|
||||
bc.e0 = e1 = e;
|
||||
|
||||
/* Summary of parsing results. The parsing stage gives values
|
||||
* s0, nd0, nd, e, y and z such that:
|
||||
* s0, nd0, nd, e, sign, where:
|
||||
*
|
||||
* - nd >= nd0 >= 1
|
||||
* - s0 points to the first significant digit of the input string s00;
|
||||
*
|
||||
* - the nd significant digits are in s0[0:nd0] and s0[nd0+1:nd+1]
|
||||
* (using the usual Python half-open slice notation)
|
||||
* - nd is the total number of significant digits (here, and
|
||||
* below, 'significant digits' means the set of digits of the
|
||||
* significand of the input that remain after ignoring leading
|
||||
* and trailing zeros.
|
||||
*
|
||||
* - 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]
|
||||
* - nd0 indicates the position of the decimal point (if
|
||||
* present): so the nd significant digits are in s0[0:nd0] and
|
||||
* s0[nd0+1:nd+1] using the usual Python half-open slice
|
||||
* notation. (If nd0 < nd, then s0[nd0] necessarily contains
|
||||
* a '.' character; if nd0 == nd, then it could be anything.)
|
||||
*
|
||||
* - the first significant digit is nonzero
|
||||
* - e is the adjusted exponent: 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 last significant digit may or may not be nonzero; (some code
|
||||
* currently assumes that it's nonzero; this is a bug)
|
||||
* - sign gives the sign of the input: 1 for negative, 0 for positive
|
||||
*
|
||||
* - the first and last significant digits are nonzero
|
||||
*/
|
||||
|
||||
/* put first DBL_DIG+1 digits into integer y and z.
|
||||
*
|
||||
* - y contains the value represented by the first min(9, nd)
|
||||
* significant digits
|
||||
|
@ -1500,6 +1515,16 @@ _Py_dg_strtod(const char *s00, char **se)
|
|||
* gives the value represented by the first min(16, nd) sig. digits.
|
||||
*/
|
||||
|
||||
y = z = 0;
|
||||
for (i = 0; i < nd; i++) {
|
||||
if (i < 9)
|
||||
y = 10*y + s0[i < nd0 ? i : i+1] - '0';
|
||||
else if (i < DBL_DIG+1)
|
||||
z = 10*z + s0[i < nd0 ? i : i+1] - '0';
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
|
||||
dval(&rv) = y;
|
||||
if (k > 9) {
|
||||
|
|
Loading…
Reference in New Issue