summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFacundo Batista <facundobatista@gmail.com>2008-01-08 12:25:20 (GMT)
committerFacundo Batista <facundobatista@gmail.com>2008-01-08 12:25:20 (GMT)
commit52b25795c02442fc40f8932d05e5d728266339a4 (patch)
tree6bd1515a655c8d46c892a9044f2aa10cf78152c8
parentf66f95d419776bdb4fe0d3c9b8d848d3321a645b (diff)
downloadcpython-52b25795c02442fc40f8932d05e5d728266339a4.zip
cpython-52b25795c02442fc40f8932d05e5d728266339a4.tar.gz
cpython-52b25795c02442fc40f8932d05e5d728266339a4.tar.bz2
Issue #1757: The hash of a Decimal instance is no longer affected
by the current context. Thanks Mark Dickinson.
-rw-r--r--Lib/decimal.py14
-rw-r--r--Lib/test/test_decimal.py17
-rw-r--r--Misc/NEWS3
3 files changed, 31 insertions, 3 deletions
diff --git a/Lib/decimal.py b/Lib/decimal.py
index 257ba0c..3ee078f 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -788,8 +788,10 @@ class Decimal(object):
def __hash__(self):
"""x.__hash__() <==> hash(x)"""
# 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._isnan():
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
# 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()))
+ # 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):
"""Represents the number as a triple tuple.
diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py
index dbe7023..03cff60 100644
--- a/Lib/test/test_decimal.py
+++ b/Lib/test/test_decimal.py
@@ -980,6 +980,23 @@ class DecimalUsabilityTest(unittest.TestCase):
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):
d1 = Decimal('15.32')
diff --git a/Misc/NEWS b/Misc/NEWS
index 4699e1b..0a01534 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -348,6 +348,9 @@ Core and builtins
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
zipfile module.