mirror of
https://github.com/python/cpython.git
synced 2025-08-27 04:05:34 +00:00
Merged revisions 79583,79588-79589 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r79583 | mark.dickinson | 2010-04-02 09:53:22 +0100 (Fri, 02 Apr 2010) | 7 lines Issue #2531: Make float-to-decimal comparisons return correct results. Float to decimal comparison operations now return a result based on the numeric values of the operands. Decimal.__hash__ has also been fixed so that Decimal and float values that compare equal have equal hash value. ........ r79588 | mark.dickinson | 2010-04-02 11:17:07 +0100 (Fri, 02 Apr 2010) | 2 lines Issue #7279: Make comparisons involving a Decimal sNaN signal InvalidOperation. ........ r79589 | mark.dickinson | 2010-04-02 11:35:12 +0100 (Fri, 02 Apr 2010) | 6 lines 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. ........
This commit is contained in:
parent
5fc16b469e
commit
ac256ab284
4 changed files with 155 additions and 27 deletions
|
@ -849,8 +849,11 @@ class Decimal(object):
|
|||
# subject of what should happen for a comparison involving a NaN.
|
||||
# We take the following approach:
|
||||
#
|
||||
# == comparisons involving a NaN always return False
|
||||
# != comparisons involving a NaN always return True
|
||||
# == comparisons involving a quiet NaN always return False
|
||||
# != comparisons involving a quiet NaN always return True
|
||||
# == or != comparisons involving a signaling NaN signal
|
||||
# InvalidOperation, and return False or True as above if the
|
||||
# InvalidOperation is not trapped.
|
||||
# <, >, <= and >= comparisons involving a (quiet or signaling)
|
||||
# NaN signal InvalidOperation, and return False if the
|
||||
# InvalidOperation is not trapped.
|
||||
|
@ -858,25 +861,25 @@ class Decimal(object):
|
|||
# This behavior is designed to conform as closely as possible to
|
||||
# that specified by IEEE 754.
|
||||
|
||||
def __eq__(self, other):
|
||||
other = _convert_other(other)
|
||||
def __eq__(self, other, context=None):
|
||||
other = _convert_other(other, allow_float=True)
|
||||
if other is NotImplemented:
|
||||
return other
|
||||
if self.is_nan() or other.is_nan():
|
||||
if self._check_nans(other, context):
|
||||
return False
|
||||
return self._cmp(other) == 0
|
||||
|
||||
def __ne__(self, other):
|
||||
other = _convert_other(other)
|
||||
def __ne__(self, other, context=None):
|
||||
other = _convert_other(other, allow_float=True)
|
||||
if other is NotImplemented:
|
||||
return other
|
||||
if self.is_nan() or other.is_nan():
|
||||
if self._check_nans(other, context):
|
||||
return True
|
||||
return self._cmp(other) != 0
|
||||
|
||||
|
||||
def __lt__(self, other, context=None):
|
||||
other = _convert_other(other)
|
||||
other = _convert_other(other, allow_float=True)
|
||||
if other is NotImplemented:
|
||||
return other
|
||||
ans = self._compare_check_nans(other, context)
|
||||
|
@ -885,7 +888,7 @@ class Decimal(object):
|
|||
return self._cmp(other) < 0
|
||||
|
||||
def __le__(self, other, context=None):
|
||||
other = _convert_other(other)
|
||||
other = _convert_other(other, allow_float=True)
|
||||
if other is NotImplemented:
|
||||
return other
|
||||
ans = self._compare_check_nans(other, context)
|
||||
|
@ -894,7 +897,7 @@ class Decimal(object):
|
|||
return self._cmp(other) <= 0
|
||||
|
||||
def __gt__(self, other, context=None):
|
||||
other = _convert_other(other)
|
||||
other = _convert_other(other, allow_float=True)
|
||||
if other is NotImplemented:
|
||||
return other
|
||||
ans = self._compare_check_nans(other, context)
|
||||
|
@ -903,7 +906,7 @@ class Decimal(object):
|
|||
return self._cmp(other) > 0
|
||||
|
||||
def __ge__(self, other, context=None):
|
||||
other = _convert_other(other)
|
||||
other = _convert_other(other, allow_float=True)
|
||||
if other is NotImplemented:
|
||||
return other
|
||||
ans = self._compare_check_nans(other, context)
|
||||
|
@ -937,12 +940,34 @@ 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')).
|
||||
|
||||
# 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._isnan():
|
||||
raise TypeError('Cannot hash a NaN value.')
|
||||
return hash(str(self))
|
||||
if not self:
|
||||
return 0
|
||||
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.
|
||||
self_as_float = float(self)
|
||||
if Decimal.from_float(self_as_float) == self:
|
||||
return hash(self_as_float)
|
||||
|
||||
if self._isinteger():
|
||||
op = _WorkRep(self.to_integral_value())
|
||||
# to make computation feasible for Decimals with large
|
||||
|
@ -5780,15 +5805,21 @@ def _log10_lb(c, correction = {
|
|||
|
||||
##### Helper Functions ####################################################
|
||||
|
||||
def _convert_other(other, raiseit=False):
|
||||
def _convert_other(other, raiseit=False, allow_float=False):
|
||||
"""Convert other to Decimal.
|
||||
|
||||
Verifies that it's ok to use in an implicit construction.
|
||||
If allow_float is true, allow conversion from float; this
|
||||
is used in the comparison methods (__eq__ and friends).
|
||||
|
||||
"""
|
||||
if isinstance(other, Decimal):
|
||||
return other
|
||||
if isinstance(other, int):
|
||||
return Decimal(other)
|
||||
if allow_float and isinstance(other, float):
|
||||
return Decimal.from_float(other)
|
||||
|
||||
if raiseit:
|
||||
raise TypeError("Unable to convert %s to Decimal" % other)
|
||||
return NotImplemented
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue