summaryrefslogtreecommitdiff
path: root/Lib/decimal.py
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2010-04-02 10:35:12 +0000
committerMark Dickinson <dickinsm@gmail.com>2010-04-02 10:35:12 +0000
commitb42e6f590eaa4d82e2781a3e6411a8f2b25d5548 (patch)
treed8991ba096d542f8ecf176062e9098099329d5a9 /Lib/decimal.py
parent87de6ebef0aab749bd09d791c90714453e06fcaa (diff)
downloadcpython-b42e6f590eaa4d82e2781a3e6411a8f2b25d5548.tar.gz
Issue #7279: Make Decimal('nan') hashable. Decimal('snan') remains unhashable.
Also rewrite the Decimal __hash__ method so that it doesn't rely on float('inf') being valid: float('inf') could raise an exception on platforms not using IEEE 754 arithmetic.
Diffstat (limited to 'Lib/decimal.py')
-rw-r--r--Lib/decimal.py24
1 files changed, 20 insertions, 4 deletions
diff --git a/Lib/decimal.py b/Lib/decimal.py
index 52ac7a8b8b..34463aefa4 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -935,14 +935,30 @@ class Decimal(object):
# 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 and self._isnan():
- raise TypeError('Cannot hash a NaN value.')
+
+ # Equality comparisons involving signaling nans can raise an
+ # exception; since equality checks are implicitly and
+ # unpredictably used when checking set and dict membership, we
+ # prevent signaling nans from being used as set elements or
+ # dict keys by making __hash__ raise an exception.
+ if self._is_special:
+ if self.is_snan():
+ raise TypeError('Cannot hash a signaling NaN value.')
+ elif self.is_nan():
+ # 0 to match hash(float('nan'))
+ return 0
+ else:
+ # values chosen to match hash(float('inf')) and
+ # hash(float('-inf')).
+ if self._sign:
+ return -271828
+ else:
+ return 314159
# In Python 2.7, we're allowing comparisons (but not
# arithmetic operations) between floats and Decimals; so if
# a Decimal instance is exactly representable as a float then
- # its hash should match that of the float. Note that this takes care
- # of zeros and infinities, as well as small integers.
+ # its hash should match that of the float.
self_as_float = float(self)
if Decimal.from_float(self_as_float) == self:
return hash(self_as_float)