Issue #11144: Fix corner cases where float-to-int conversion unnecessarily returned a long.
This commit is contained in:
parent
d3cb2f6e2c
commit
874d59ee91
|
@ -52,6 +52,48 @@ class GeneralFloatCases(unittest.TestCase):
|
||||||
float('.' + '1'*1000)
|
float('.' + '1'*1000)
|
||||||
float(unicode('.' + '1'*1000))
|
float(unicode('.' + '1'*1000))
|
||||||
|
|
||||||
|
def check_conversion_to_int(self, x):
|
||||||
|
"""Check that int(x) has the correct value and type, for a float x."""
|
||||||
|
n = int(x)
|
||||||
|
if x >= 0.0:
|
||||||
|
# x >= 0 and n = int(x) ==> n <= x < n + 1
|
||||||
|
self.assertLessEqual(n, x)
|
||||||
|
self.assertLess(x, n + 1)
|
||||||
|
else:
|
||||||
|
# x < 0 and n = int(x) ==> n >= x > n - 1
|
||||||
|
self.assertGreaterEqual(n, x)
|
||||||
|
self.assertGreater(x, n - 1)
|
||||||
|
|
||||||
|
# Result should be an int if within range, else a long.
|
||||||
|
if -sys.maxint-1 <= n <= sys.maxint:
|
||||||
|
self.assertEqual(type(n), int)
|
||||||
|
else:
|
||||||
|
self.assertEqual(type(n), long)
|
||||||
|
|
||||||
|
# Double check.
|
||||||
|
self.assertEqual(type(int(n)), type(n))
|
||||||
|
|
||||||
|
def test_conversion_to_int(self):
|
||||||
|
# Check that floats within the range of an int convert to type
|
||||||
|
# int, not long. (issue #11144.)
|
||||||
|
boundary = float(sys.maxint + 1)
|
||||||
|
epsilon = 2**-sys.float_info.mant_dig * boundary
|
||||||
|
|
||||||
|
# These 2 floats are either side of the positive int/long boundary on
|
||||||
|
# both 32-bit and 64-bit systems.
|
||||||
|
self.check_conversion_to_int(boundary - epsilon)
|
||||||
|
self.check_conversion_to_int(boundary)
|
||||||
|
|
||||||
|
# These floats are either side of the negative long/int boundary on
|
||||||
|
# 64-bit systems...
|
||||||
|
self.check_conversion_to_int(-boundary - 2*epsilon)
|
||||||
|
self.check_conversion_to_int(-boundary)
|
||||||
|
|
||||||
|
# ... and these ones are either side of the negative long/int
|
||||||
|
# boundary on 32-bit systems.
|
||||||
|
self.check_conversion_to_int(-boundary - 1.0)
|
||||||
|
self.check_conversion_to_int(-boundary - 1.0 + 2*epsilon)
|
||||||
|
|
||||||
@test_support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
|
@test_support.run_with_locale('LC_NUMERIC', 'fr_FR', 'de_DE')
|
||||||
def test_float_with_comma(self):
|
def test_float_with_comma(self):
|
||||||
# set locale to something that doesn't use '.' for the decimal point
|
# set locale to something that doesn't use '.' for the decimal point
|
||||||
|
|
|
@ -9,6 +9,10 @@ What's New in Python 2.7.2?
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #11144: Ensure that int(a_float) returns an int whenever possible.
|
||||||
|
Previously, there were some corner cases where a long was returned even
|
||||||
|
though the result was within the range of an int.
|
||||||
|
|
||||||
- Issue #11675: multiprocessing.[Raw]Array objects created from an integer size
|
- Issue #11675: multiprocessing.[Raw]Array objects created from an integer size
|
||||||
are now zeroed on creation. This matches the behaviour specified by the
|
are now zeroed on creation. This matches the behaviour specified by the
|
||||||
documentation.
|
documentation.
|
||||||
|
|
|
@ -1035,14 +1035,17 @@ float_trunc(PyObject *v)
|
||||||
* happens if the double is too big to fit in a long. Some rare
|
* happens if the double is too big to fit in a long. Some rare
|
||||||
* systems raise an exception then (RISCOS was mentioned as one,
|
* systems raise an exception then (RISCOS was mentioned as one,
|
||||||
* and someone using a non-default option on Sun also bumped into
|
* and someone using a non-default option on Sun also bumped into
|
||||||
* that). Note that checking for >= and <= LONG_{MIN,MAX} would
|
* that). Note that checking for <= LONG_MAX is unsafe: if a long
|
||||||
* still be vulnerable: if a long has more bits of precision than
|
* has more bits of precision than a double, casting LONG_MAX to
|
||||||
* a double, casting MIN/MAX to double may yield an approximation,
|
* double may yield an approximation, and if that's rounded up,
|
||||||
* and if that's rounded up, then, e.g., wholepart=LONG_MAX+1 would
|
* then, e.g., wholepart=LONG_MAX+1 would yield true from the C
|
||||||
* yield true from the C expression wholepart<=LONG_MAX, despite
|
* expression wholepart<=LONG_MAX, despite that wholepart is
|
||||||
* that wholepart is actually greater than LONG_MAX.
|
* actually greater than LONG_MAX. However, assuming a two's complement
|
||||||
|
* machine with no trap representation, LONG_MIN will be a power of 2 (and
|
||||||
|
* hence exactly representable as a double), and LONG_MAX = -1-LONG_MIN, so
|
||||||
|
* the comparisons with (double)LONG_MIN below should be safe.
|
||||||
*/
|
*/
|
||||||
if (LONG_MIN < wholepart && wholepart < LONG_MAX) {
|
if ((double)LONG_MIN <= wholepart && wholepart < -(double)LONG_MIN) {
|
||||||
const long aslong = (long)wholepart;
|
const long aslong = (long)wholepart;
|
||||||
return PyInt_FromLong(aslong);
|
return PyInt_FromLong(aslong);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue