mirror of
https://github.com/python/cpython.git
synced 2025-07-29 14:15:07 +00:00
Issue #1772851. Optimization of __hash__ to behave better for big big
numbers.
This commit is contained in:
parent
ae406c6018
commit
8c20244069
2 changed files with 43 additions and 4 deletions
|
@ -766,10 +766,17 @@ class Decimal(object):
|
||||||
if self._isnan():
|
if self._isnan():
|
||||||
raise TypeError('Cannot hash a NaN value.')
|
raise TypeError('Cannot hash a NaN value.')
|
||||||
return hash(str(self))
|
return hash(str(self))
|
||||||
i = int(self)
|
if not self:
|
||||||
if self == Decimal(i):
|
return 0
|
||||||
return hash(i)
|
if self._isinteger():
|
||||||
assert self.__nonzero__() # '-0' handled by integer case
|
op = _WorkRep(self.to_integral_value())
|
||||||
|
# to make computation feasible for Decimals with large
|
||||||
|
# exponent, we use the fact that hash(n) == hash(m) for
|
||||||
|
# any two nonzero integers n and m such that (i) n and m
|
||||||
|
# have the same sign, and (ii) n is congruent to m modulo
|
||||||
|
# 2**64-1. So we can replace hash((-1)**s*c*10**e) with
|
||||||
|
# hash((-1)**s*c*pow(10, e, 2**64-1).
|
||||||
|
return hash((-1)**op.sign*op.int*pow(10, op.exp, 2**64-1))
|
||||||
return hash(str(self.normalize()))
|
return hash(str(self.normalize()))
|
||||||
|
|
||||||
def as_tuple(self):
|
def as_tuple(self):
|
||||||
|
|
|
@ -910,6 +910,38 @@ class DecimalUsabilityTest(unittest.TestCase):
|
||||||
def test_hash_method(self):
|
def test_hash_method(self):
|
||||||
#just that it's hashable
|
#just that it's hashable
|
||||||
hash(Decimal(23))
|
hash(Decimal(23))
|
||||||
|
|
||||||
|
test_values = [Decimal(sign*(2**m + n))
|
||||||
|
for m in [0, 14, 15, 16, 17, 30, 31,
|
||||||
|
32, 33, 62, 63, 64, 65, 66]
|
||||||
|
for n in range(-10, 10)
|
||||||
|
for sign in [-1, 1]]
|
||||||
|
test_values.extend([
|
||||||
|
Decimal("-0"), # zeros
|
||||||
|
Decimal("0.00"),
|
||||||
|
Decimal("-0.000"),
|
||||||
|
Decimal("0E10"),
|
||||||
|
Decimal("-0E12"),
|
||||||
|
Decimal("10.0"), # negative exponent
|
||||||
|
Decimal("-23.00000"),
|
||||||
|
Decimal("1230E100"), # positive exponent
|
||||||
|
Decimal("-4.5678E50"),
|
||||||
|
# a value for which hash(n) != hash(n % (2**64-1))
|
||||||
|
# in Python pre-2.6
|
||||||
|
Decimal(2**64 + 2**32 - 1),
|
||||||
|
# selection of values which fail with the old (before
|
||||||
|
# version 2.6) long.__hash__
|
||||||
|
Decimal("1.634E100"),
|
||||||
|
Decimal("90.697E100"),
|
||||||
|
Decimal("188.83E100"),
|
||||||
|
Decimal("1652.9E100"),
|
||||||
|
Decimal("56531E100"),
|
||||||
|
])
|
||||||
|
|
||||||
|
# check that hash(d) == hash(int(d)) for integral values
|
||||||
|
for value in test_values:
|
||||||
|
self.assertEqual(hash(value), hash(int(value)))
|
||||||
|
|
||||||
#the same hash that to an int
|
#the same hash that to an int
|
||||||
self.assertEqual(hash(Decimal(23)), hash(23))
|
self.assertEqual(hash(Decimal(23)), hash(23))
|
||||||
self.assertRaises(TypeError, hash, Decimal('NaN'))
|
self.assertRaises(TypeError, hash, Decimal('NaN'))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue