Issue #1757: The hash of a Decimal instance is no longer affected

by the current context.  Thanks Mark Dickinson.
This commit is contained in:
Facundo Batista 2008-01-08 12:25:20 +00:00
parent f66f95d419
commit 52b25795c0
3 changed files with 31 additions and 3 deletions

View File

@ -788,8 +788,10 @@ class Decimal(object):
def __hash__(self): def __hash__(self):
"""x.__hash__() <==> hash(x)""" """x.__hash__() <==> hash(x)"""
# Decimal integers must hash the same as the ints # Decimal integers must hash the same as the ints
# Non-integer decimals are normalized and hashed as strings #
# Normalization assures that hash(100E-1) == hash(10) # The hash of a nonspecial noninteger Decimal must depend only
# on the value of that Decimal, and not on its representation.
# For example: hash(Decimal("100E-1")) == hash(Decimal("10")).
if self._is_special: if self._is_special:
if self._isnan(): if self._isnan():
raise TypeError('Cannot hash a NaN value.') raise TypeError('Cannot hash a NaN value.')
@ -805,7 +807,13 @@ class Decimal(object):
# 2**64-1. So we can replace hash((-1)**s*c*10**e) with # 2**64-1. So we can replace hash((-1)**s*c*10**e) with
# hash((-1)**s*c*pow(10, e, 2**64-1). # 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((-1)**op.sign*op.int*pow(10, op.exp, 2**64-1))
return hash(str(self.normalize())) # The value of a nonzero nonspecial Decimal instance is
# faithfully represented by the triple consisting of its sign,
# its adjusted exponent, and its coefficient with trailing
# zeros removed.
return hash((self._sign,
self._exp+len(self._int),
self._int.rstrip('0')))
def as_tuple(self): def as_tuple(self):
"""Represents the number as a triple tuple. """Represents the number as a triple tuple.

View File

@ -980,6 +980,23 @@ class DecimalUsabilityTest(unittest.TestCase):
self.assert_(hash(Decimal('Inf'))) self.assert_(hash(Decimal('Inf')))
self.assert_(hash(Decimal('-Inf'))) self.assert_(hash(Decimal('-Inf')))
# check that the value of the hash doesn't depend on the
# current context (issue #1757)
c = getcontext()
old_precision = c.prec
x = Decimal("123456789.1")
c.prec = 6
h1 = hash(x)
c.prec = 10
h2 = hash(x)
c.prec = 16
h3 = hash(x)
self.assertEqual(h1, h2)
self.assertEqual(h1, h3)
c.prec = old_precision
def test_min_and_max_methods(self): def test_min_and_max_methods(self):
d1 = Decimal('15.32') d1 = Decimal('15.32')

View File

@ -348,6 +348,9 @@ Core and builtins
Library Library
------- -------
- Issue #1757: The hash of a Decimal instance is no longer affected by
the current context.
- Patch #467924: add ZipFile.extract() and ZipFile.extractall() in the - Patch #467924: add ZipFile.extract() and ZipFile.extractall() in the
zipfile module. zipfile module.