[Python-checkins] r79589 - in python/trunk: Lib/decimal.py Lib/test/test_decimal.py Misc/NEWS
mark.dickinson
python-checkins at python.org
Fri Apr 2 12:35:12 CEST 2010
Author: mark.dickinson
Date: Fri Apr 2 12:35:12 2010
New Revision: 79589
Log:
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.
Modified:
python/trunk/Lib/decimal.py
python/trunk/Lib/test/test_decimal.py
python/trunk/Misc/NEWS
Modified: python/trunk/Lib/decimal.py
==============================================================================
--- python/trunk/Lib/decimal.py (original)
+++ python/trunk/Lib/decimal.py Fri Apr 2 12:35:12 2010
@@ -935,14 +935,30 @@
# 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)
Modified: python/trunk/Lib/test/test_decimal.py
==============================================================================
--- python/trunk/Lib/test/test_decimal.py (original)
+++ python/trunk/Lib/test/test_decimal.py Fri Apr 2 12:35:12 2010
@@ -1274,6 +1274,10 @@
def test_hash_method(self):
#just that it's hashable
hash(Decimal(23))
+ hash(Decimal('Infinity'))
+ hash(Decimal('-Infinity'))
+ hash(Decimal('nan123'))
+ hash(Decimal('-NaN'))
test_values = [Decimal(sign*(2**m + n))
for m in [0, 14, 15, 16, 17, 30, 31,
@@ -1308,7 +1312,7 @@
#the same hash that to an int
self.assertEqual(hash(Decimal(23)), hash(23))
- self.assertRaises(TypeError, hash, Decimal('NaN'))
+ self.assertRaises(TypeError, hash, Decimal('sNaN'))
self.assertTrue(hash(Decimal('Inf')))
self.assertTrue(hash(Decimal('-Inf')))
Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS (original)
+++ python/trunk/Misc/NEWS Fri Apr 2 12:35:12 2010
@@ -37,7 +37,8 @@
- Issue #7279: Comparisons involving a Decimal signaling NaN now
signal InvalidOperation instead of returning False. (Comparisons
- involving a quiet NaN are unchanged.)
+ involving a quiet NaN are unchanged.) Also, Decimal quiet NaNs
+ are now hashable; Decimal signaling NaNs remain unhashable.
- Issue #2531: Comparison operations between floats and Decimal
instances now return a result based on the numeric values of the
More information about the Python-checkins
mailing list