diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2010-01-14 14:40:20 (GMT) |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2010-01-14 14:40:20 (GMT) |
commit | f8747c1f12577a4198d47f28eaf89a2983a13261 (patch) | |
tree | cdb584b89986d028db208b6efa132bbf19669be1 /Python | |
parent | 50b60c612e7eca3f815d362190ddb80a21a6d820 (diff) | |
download | cpython-f8747c1f12577a4198d47f28eaf89a2983a13261.zip cpython-f8747c1f12577a4198d47f28eaf89a2983a13261.tar.gz cpython-f8747c1f12577a4198d47f28eaf89a2983a13261.tar.bz2 |
Issue 7632: fix incorrect rounding for long input strings with values very close to a power of 2. (See Bug 4 in the tracker discussion.)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/dtoa.c | 24 |
1 files changed, 24 insertions, 0 deletions
diff --git a/Python/dtoa.c b/Python/dtoa.c index 5637c6c..51895c7 100644 --- a/Python/dtoa.c +++ b/Python/dtoa.c @@ -1738,6 +1738,30 @@ _Py_dg_strtod(const char *s00, char **se) if (bc.nd > nd && i <= 0) { if (bc.dsign) break; /* Must use bigcomp(). */ + + /* Here rv overestimates the truncated decimal value by at most + 0.5 ulp(rv). Hence rv either overestimates the true decimal + value by <= 0.5 ulp(rv), or underestimates it by some small + amount (< 0.1 ulp(rv)); either way, rv is within 0.5 ulps of + the true decimal value, so it's possible to exit. + + Exception: if scaled rv is a normal exact power of 2, but not + DBL_MIN, then rv - 0.5 ulp(rv) takes us all the way down to the + next double, so the correctly rounded result is either rv - 0.5 + ulp(rv) or rv; in this case, use bigcomp to distinguish. */ + + if (!word1(&rv) && !(word0(&rv) & Bndry_mask)) { + /* rv can't be 0, since it's an overestimate for some + nonzero value. So rv is a normal power of 2. */ + j = (int)(word0(&rv) & Exp_mask) >> Exp_shift; + /* rv / 2^bc.scale = 2^(j - 1023 - bc.scale); use bigcomp if + rv / 2^bc.scale >= 2^-1021. */ + if (j - bc.scale >= 2) { + dval(&rv) -= 0.5 * sulp(&rv, &bc); + break; + } + } + { bc.nd = nd; i = -1; /* Discarded digits make delta smaller. */ |