diff options
author | Mark Dickinson <dickinsm@gmail.com> | 2010-04-02 10:35:12 +0000 |
---|---|---|
committer | Mark Dickinson <dickinsm@gmail.com> | 2010-04-02 10:35:12 +0000 |
commit | b42e6f590eaa4d82e2781a3e6411a8f2b25d5548 (patch) | |
tree | d8991ba096d542f8ecf176062e9098099329d5a9 /Lib/decimal.py | |
parent | 87de6ebef0aab749bd09d791c90714453e06fcaa (diff) | |
download | cpython-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.py | 24 |
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) |