mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
Merged revisions 77519,77530,77533 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r77519 | mark.dickinson | 2010-01-16 10:44:00 +0000 (Sat, 16 Jan 2010) | 5 lines 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. ........ r77530 | mark.dickinson | 2010-01-16 17:57:49 +0000 (Sat, 16 Jan 2010) | 3 lines Issue #7632: Fix one more case of incorrect rounding for str -> float conversion (see bug 5 in the issue tracker). ........ r77533 | mark.dickinson | 2010-01-16 18:06:17 +0000 (Sat, 16 Jan 2010) | 1 line Fix multiple uses of variable 'L' in _Py_dg_strtod, where one use requires an unsigned long and the other a signed long. See also r77421. ........
This commit is contained in:
parent
747e8b3f58
commit
45b6365974
3 changed files with 100 additions and 47 deletions
|
@ -123,10 +123,6 @@ class StrtodTests(unittest.TestCase):
|
||||||
digits = m * 5**-e
|
digits = m * 5**-e
|
||||||
exponent = e
|
exponent = e
|
||||||
s = '{}e{}'.format(digits, exponent)
|
s = '{}e{}'.format(digits, exponent)
|
||||||
|
|
||||||
# for the moment, ignore errors from trailing zeros
|
|
||||||
if digits % 10 == 0:
|
|
||||||
continue
|
|
||||||
self.check_strtod(s)
|
self.check_strtod(s)
|
||||||
|
|
||||||
# get expected answer via struct, to triple check
|
# get expected answer via struct, to triple check
|
||||||
|
@ -175,7 +171,8 @@ class StrtodTests(unittest.TestCase):
|
||||||
self.check_strtod(s)
|
self.check_strtod(s)
|
||||||
|
|
||||||
def test_parsing(self):
|
def test_parsing(self):
|
||||||
digits = tuple(map(str, range(10)))
|
# make '0' more likely to be chosen than other digits
|
||||||
|
digits = '000000123456789'
|
||||||
signs = ('+', '-', '')
|
signs = ('+', '-', '')
|
||||||
|
|
||||||
# put together random short valid strings
|
# put together random short valid strings
|
||||||
|
@ -257,7 +254,9 @@ class StrtodTests(unittest.TestCase):
|
||||||
'247032822920623295e-341',
|
'247032822920623295e-341',
|
||||||
# issue 7632 bug 5: the following 2 strings convert differently
|
# issue 7632 bug 5: the following 2 strings convert differently
|
||||||
'1000000000000000000000000000000000000000e-16',
|
'1000000000000000000000000000000000000000e-16',
|
||||||
#'10000000000000000000000000000000000000000e-17',
|
'10000000000000000000000000000000000000000e-17',
|
||||||
|
# issue 7632 bug 8: the following produced 10.0
|
||||||
|
'10.900000000000000012345678912345678912345',
|
||||||
]
|
]
|
||||||
for s in test_strings:
|
for s in test_strings:
|
||||||
self.check_strtod(s)
|
self.check_strtod(s)
|
||||||
|
|
10
Misc/NEWS
10
Misc/NEWS
|
@ -16,10 +16,12 @@ Core and Builtins
|
||||||
methods of bytes, bytearray and unicode objects by using a common
|
methods of bytes, bytearray and unicode objects by using a common
|
||||||
implementation based on stringlib's fast search. Patch by Florent Xicluna.
|
implementation based on stringlib's fast search. Patch by Florent Xicluna.
|
||||||
|
|
||||||
- Issue #7632: Fix a crash in dtoa.c that occurred in debug builds
|
- Issue #7632: Fix various str -> float conversion bugs present in 2.7
|
||||||
when parsing certain long numeric strings corresponding to subnormal
|
alpha 2, including: (1) a serious 'wrong output' bug that could
|
||||||
values. Also fix a number of bugs in dtoa.c that could lead to
|
occur for long (> 40 digit) input strings, (2) a crash in dtoa.c
|
||||||
incorrectly rounded results when converting strings to floats.
|
that occurred in debug builds when parsing certain long numeric
|
||||||
|
strings corresponding to subnormal values, and (3) a number of flaws
|
||||||
|
that could lead to incorrectly rounded results.
|
||||||
|
|
||||||
- The __complex__ method is now looked up on the class of instances to make it
|
- The __complex__ method is now looked up on the class of instances to make it
|
||||||
consistent with other special methods.
|
consistent with other special methods.
|
||||||
|
|
126
Python/dtoa.c
126
Python/dtoa.c
|
@ -1340,16 +1340,17 @@ 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, 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;
|
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;
|
||||||
U aadj2, adj, rv, rv0;
|
U aadj2, adj, rv, rv0;
|
||||||
ULong y, z, L;
|
ULong y, z, abse;
|
||||||
|
Long L;
|
||||||
BCinfo bc;
|
BCinfo bc;
|
||||||
Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
|
Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
|
||||||
|
|
||||||
sign = nz0 = nz = dplen = 0;
|
sign = nz0 = nz = 0;
|
||||||
dval(&rv) = 0.;
|
dval(&rv) = 0.;
|
||||||
for(s = s00;;s++) switch(*s) {
|
for(s = s00;;s++) switch(*s) {
|
||||||
case '-':
|
case '-':
|
||||||
|
@ -1381,18 +1382,11 @@ _Py_dg_strtod(const char *s00, char **se)
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
s0 = s;
|
s0 = s;
|
||||||
y = z = 0;
|
|
||||||
for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
|
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;
|
nd0 = nd;
|
||||||
dp0 = dp1 = s - s0;
|
|
||||||
if (c == '.') {
|
if (c == '.') {
|
||||||
c = *++s;
|
c = *++s;
|
||||||
dp1 = s - s0;
|
|
||||||
dplen = 1;
|
|
||||||
if (!nd) {
|
if (!nd) {
|
||||||
for(; c == '0'; c = *++s)
|
for(; c == '0'; c = *++s)
|
||||||
nz++;
|
nz++;
|
||||||
|
@ -1409,15 +1403,7 @@ _Py_dg_strtod(const char *s00, char **se)
|
||||||
nz++;
|
nz++;
|
||||||
if (c -= '0') {
|
if (c -= '0') {
|
||||||
nf += nz;
|
nf += nz;
|
||||||
for(i = 1; i < nz; i++)
|
nd += nz;
|
||||||
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;
|
|
||||||
nz = 0;
|
nz = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1440,17 +1426,17 @@ _Py_dg_strtod(const char *s00, char **se)
|
||||||
while(c == '0')
|
while(c == '0')
|
||||||
c = *++s;
|
c = *++s;
|
||||||
if (c > '0' && c <= '9') {
|
if (c > '0' && c <= '9') {
|
||||||
L = c - '0';
|
abse = c - '0';
|
||||||
s1 = s;
|
s1 = s;
|
||||||
while((c = *++s) >= '0' && c <= '9')
|
while((c = *++s) >= '0' && c <= '9')
|
||||||
L = 10*L + c - '0';
|
abse = 10*abse + c - '0';
|
||||||
if (s - s1 > 8 || L > MAX_ABS_EXP)
|
if (s - s1 > 8 || abse > MAX_ABS_EXP)
|
||||||
/* Avoid confusion from exponents
|
/* Avoid confusion from exponents
|
||||||
* so large that e might overflow.
|
* so large that e might overflow.
|
||||||
*/
|
*/
|
||||||
e = (int)MAX_ABS_EXP; /* safe for 16 bit ints */
|
e = (int)MAX_ABS_EXP; /* safe for 16 bit ints */
|
||||||
else
|
else
|
||||||
e = (int)L;
|
e = (int)abse;
|
||||||
if (esign)
|
if (esign)
|
||||||
e = -e;
|
e = -e;
|
||||||
}
|
}
|
||||||
|
@ -1468,15 +1454,78 @@ _Py_dg_strtod(const char *s00, char **se)
|
||||||
}
|
}
|
||||||
goto ret;
|
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
|
/* Now we have nd0 digits, starting at s0, followed by a
|
||||||
* decimal point, followed by nd-nd0 digits. The number we're
|
* decimal point, followed by nd-nd0 digits. The number we're
|
||||||
* after is the integer represented by those digits times
|
* after is the integer represented by those digits times
|
||||||
* 10**e */
|
* 10**e */
|
||||||
|
|
||||||
if (!nd0)
|
bc.e0 = e1 = e;
|
||||||
nd0 = nd;
|
|
||||||
|
/* Summary of parsing results. The parsing stage gives values
|
||||||
|
* s0, nd0, nd, e, sign, where:
|
||||||
|
*
|
||||||
|
* - s0 points to the first significant digit of the input string s00;
|
||||||
|
*
|
||||||
|
* - 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.
|
||||||
|
*
|
||||||
|
* - 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.)
|
||||||
|
*
|
||||||
|
* - 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]
|
||||||
|
*
|
||||||
|
* - 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
|
||||||
|
*
|
||||||
|
* - 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
|
||||||
dval(&rv) = y;
|
dval(&rv) = y;
|
||||||
if (k > 9) {
|
if (k > 9) {
|
||||||
|
@ -1593,15 +1642,18 @@ _Py_dg_strtod(const char *s00, char **se)
|
||||||
/* ASSERT(STRTOD_DIGLIM >= 18); 18 == one more than the */
|
/* ASSERT(STRTOD_DIGLIM >= 18); 18 == one more than the */
|
||||||
/* minimum number of decimal digits to distinguish double values */
|
/* minimum number of decimal digits to distinguish double values */
|
||||||
/* in IEEE arithmetic. */
|
/* in IEEE arithmetic. */
|
||||||
i = j = 18;
|
|
||||||
if (i > nd0)
|
/* Truncate input to 18 significant digits, then discard any trailing
|
||||||
j += dplen;
|
zeros on the result by updating nd, nd0, e and y suitably. (There's
|
||||||
for(;;) {
|
no need to update z; it's not reused beyond this point.) */
|
||||||
if (--j <= dp1 && j >= dp0)
|
for (i = 18; i > 0; ) {
|
||||||
j = dp0 - 1;
|
/* scan back until we hit a nonzero digit. significant digit 'i'
|
||||||
if (s0[j] != '0')
|
is s0[i] if i < nd0, s0[i+1] if i >= nd0. */
|
||||||
break;
|
|
||||||
--i;
|
--i;
|
||||||
|
if (s0[i < nd0 ? i : i+1] != '0') {
|
||||||
|
++i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
e += nd - i;
|
e += nd - i;
|
||||||
nd = i;
|
nd = i;
|
||||||
|
@ -1611,8 +1663,8 @@ _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 = dp1; i < nd; ++i)
|
for(; i < nd; ++i)
|
||||||
y = 10*y + s0[j++] - '0';
|
y = 10*y + s0[i+1] - '0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bd0 = s2b(s0, nd0, nd, y);
|
bd0 = s2b(s0, nd0, nd, y);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue