mirror of
https://github.com/python/cpython.git
synced 2025-09-27 18:59:43 +00:00
bpo-43475: Fix the Python implementation of hash of Decimal NaN (GH-26679)
(cherry picked from commit 9f1c5f6e8a
)
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
This commit is contained in:
parent
4becc569a6
commit
128899d8b8
4 changed files with 36 additions and 10 deletions
|
@ -739,7 +739,7 @@ number, :class:`float`, or :class:`complex`::
|
||||||
"""Compute the hash of a float x."""
|
"""Compute the hash of a float x."""
|
||||||
|
|
||||||
if math.isnan(x):
|
if math.isnan(x):
|
||||||
return super().__hash__()
|
return object.__hash__(x)
|
||||||
elif math.isinf(x):
|
elif math.isinf(x):
|
||||||
return sys.hash_info.inf if x > 0 else -sys.hash_info.inf
|
return sys.hash_info.inf if x > 0 else -sys.hash_info.inf
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -951,7 +951,7 @@ class Decimal(object):
|
||||||
if self.is_snan():
|
if self.is_snan():
|
||||||
raise TypeError('Cannot hash a signaling NaN value.')
|
raise TypeError('Cannot hash a signaling NaN value.')
|
||||||
elif self.is_nan():
|
elif self.is_nan():
|
||||||
return super().__hash__()
|
return object.__hash__(self)
|
||||||
else:
|
else:
|
||||||
if self._sign:
|
if self._sign:
|
||||||
return -_PyHASH_INF
|
return -_PyHASH_INF
|
||||||
|
|
|
@ -1814,13 +1814,7 @@ class UsabilityTest(unittest.TestCase):
|
||||||
|
|
||||||
# check that hash(d) == hash(int(d)) for integral values
|
# check that hash(d) == hash(int(d)) for integral values
|
||||||
for value in test_values:
|
for value in test_values:
|
||||||
self.assertEqual(hashit(value), hashit(int(value)))
|
self.assertEqual(hashit(value), hash(int(value)))
|
||||||
|
|
||||||
#the same hash that to an int
|
|
||||||
self.assertEqual(hashit(Decimal(23)), hashit(23))
|
|
||||||
self.assertRaises(TypeError, hash, Decimal('sNaN'))
|
|
||||||
self.assertTrue(hashit(Decimal('Inf')))
|
|
||||||
self.assertTrue(hashit(Decimal('-Inf')))
|
|
||||||
|
|
||||||
# check that the hashes of a Decimal float match when they
|
# check that the hashes of a Decimal float match when they
|
||||||
# represent exactly the same values
|
# represent exactly the same values
|
||||||
|
@ -1829,7 +1823,7 @@ class UsabilityTest(unittest.TestCase):
|
||||||
for s in test_strings:
|
for s in test_strings:
|
||||||
f = float(s)
|
f = float(s)
|
||||||
d = Decimal(s)
|
d = Decimal(s)
|
||||||
self.assertEqual(hashit(f), hashit(d))
|
self.assertEqual(hashit(d), hash(f))
|
||||||
|
|
||||||
with localcontext() as c:
|
with localcontext() as c:
|
||||||
# check that the value of the hash doesn't depend on the
|
# check that the value of the hash doesn't depend on the
|
||||||
|
@ -1850,6 +1844,19 @@ class UsabilityTest(unittest.TestCase):
|
||||||
x = 1100 ** 1248
|
x = 1100 ** 1248
|
||||||
self.assertEqual(hashit(Decimal(x)), hashit(x))
|
self.assertEqual(hashit(Decimal(x)), hashit(x))
|
||||||
|
|
||||||
|
def test_hash_method_nan(self):
|
||||||
|
Decimal = self.decimal.Decimal
|
||||||
|
self.assertRaises(TypeError, hash, Decimal('sNaN'))
|
||||||
|
value = Decimal('NaN')
|
||||||
|
self.assertEqual(hash(value), object.__hash__(value))
|
||||||
|
class H:
|
||||||
|
def __hash__(self):
|
||||||
|
return 42
|
||||||
|
class D(Decimal, H):
|
||||||
|
pass
|
||||||
|
value = D('NaN')
|
||||||
|
self.assertEqual(hash(value), object.__hash__(value))
|
||||||
|
|
||||||
def test_min_and_max_methods(self):
|
def test_min_and_max_methods(self):
|
||||||
Decimal = self.decimal.Decimal
|
Decimal = self.decimal.Decimal
|
||||||
|
|
||||||
|
|
|
@ -564,6 +564,25 @@ class GeneralFloatCases(unittest.TestCase):
|
||||||
#self.assertTrue(0.0 < pow_op(2.0, -1047) < 1e-315)
|
#self.assertTrue(0.0 < pow_op(2.0, -1047) < 1e-315)
|
||||||
#self.assertTrue(0.0 > pow_op(-2.0, -1047) > -1e-315)
|
#self.assertTrue(0.0 > pow_op(-2.0, -1047) > -1e-315)
|
||||||
|
|
||||||
|
def test_hash(self):
|
||||||
|
for x in range(-30, 30):
|
||||||
|
self.assertEqual(hash(float(x)), hash(x))
|
||||||
|
self.assertEqual(hash(float(sys.float_info.max)),
|
||||||
|
hash(int(sys.float_info.max)))
|
||||||
|
self.assertEqual(hash(float('inf')), sys.hash_info.inf)
|
||||||
|
self.assertEqual(hash(float('-inf')), -sys.hash_info.inf)
|
||||||
|
|
||||||
|
def test_hash_nan(self):
|
||||||
|
value = float('nan')
|
||||||
|
self.assertEqual(hash(value), object.__hash__(value))
|
||||||
|
class H:
|
||||||
|
def __hash__(self):
|
||||||
|
return 42
|
||||||
|
class F(float, H):
|
||||||
|
pass
|
||||||
|
value = F('nan')
|
||||||
|
self.assertEqual(hash(value), object.__hash__(value))
|
||||||
|
|
||||||
|
|
||||||
@requires_setformat
|
@requires_setformat
|
||||||
class FormatFunctionsTestCase(unittest.TestCase):
|
class FormatFunctionsTestCase(unittest.TestCase):
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue