[Python-checkins] r79588 - in python/trunk: Lib/decimal.py Lib/test/test_decimal.py Misc/NEWS
mark.dickinson
python-checkins at python.org
Fri Apr 2 12:17:07 CEST 2010
Author: mark.dickinson
Date: Fri Apr 2 12:17:07 2010
New Revision: 79588
Log:
Issue #7279: Make comparisons involving a Decimal sNaN signal InvalidOperation.
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:17:07 2010
@@ -845,8 +845,11 @@
# 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.
@@ -854,19 +857,19 @@
# This behavior is designed to conform as closely as possible to
# that specified by IEEE 754.
- def __eq__(self, 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):
+ 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
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:17:07 2010
@@ -26,6 +26,7 @@
import math
import os, sys
+import operator
import pickle, copy
import unittest
from decimal import *
@@ -1080,18 +1081,56 @@
self.assertEqual(abs(Decimal(45)), abs(Decimal(-45))) # abs
def test_nan_comparisons(self):
+ # comparisons involving signaling nans signal InvalidOperation
+
+ # order comparisons (<, <=, >, >=) involving only quiet nans
+ # also signal InvalidOperation
+
+ # equality comparisons (==, !=) involving only quiet nans
+ # don't signal, but return False or True respectively.
+
n = Decimal('NaN')
s = Decimal('sNaN')
i = Decimal('Inf')
f = Decimal('2')
- for x, y in [(n, n), (n, i), (i, n), (n, f), (f, n),
- (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)]:
- self.assertTrue(x != y)
- self.assertTrue(not (x == y))
- self.assertTrue(not (x < y))
- self.assertTrue(not (x <= y))
- self.assertTrue(not (x > y))
- self.assertTrue(not (x >= y))
+
+ qnan_pairs = (n, n), (n, i), (i, n), (n, f), (f, n)
+ snan_pairs = (s, n), (n, s), (s, i), (i, s), (s, f), (f, s), (s, s)
+ order_ops = operator.lt, operator.le, operator.gt, operator.ge
+ equality_ops = operator.eq, operator.ne
+
+ # results when InvalidOperation is not trapped
+ for x, y in qnan_pairs + snan_pairs:
+ for op in order_ops + equality_ops:
+ got = op(x, y)
+ expected = True if op is operator.ne else False
+ self.assertIs(expected, got,
+ "expected {0!r} for operator.{1}({2!r}, {3!r}); "
+ "got {4!r}".format(
+ expected, op.__name__, x, y, got))
+
+ # repeat the above, but this time trap the InvalidOperation
+ with localcontext() as ctx:
+ ctx.traps[InvalidOperation] = 1
+
+ for x, y in qnan_pairs:
+ for op in equality_ops:
+ got = op(x, y)
+ expected = True if op is operator.ne else False
+ self.assertIs(expected, got,
+ "expected {0!r} for "
+ "operator.{1}({2!r}, {3!r}); "
+ "got {4!r}".format(
+ expected, op.__name__, x, y, got))
+
+ for x, y in snan_pairs:
+ for op in equality_ops:
+ self.assertRaises(InvalidOperation, operator.eq, x, y)
+ self.assertRaises(InvalidOperation, operator.ne, x, y)
+
+ for x, y in qnan_pairs + snan_pairs:
+ for op in order_ops:
+ self.assertRaises(InvalidOperation, op, x, y)
def test_copy_sign(self):
d = Decimal(1).copy_sign(Decimal(-2))
Modified: python/trunk/Misc/NEWS
==============================================================================
--- python/trunk/Misc/NEWS (original)
+++ python/trunk/Misc/NEWS Fri Apr 2 12:17:07 2010
@@ -35,6 +35,10 @@
Library
-------
+- Issue #7279: Comparisons involving a Decimal signaling NaN now
+ signal InvalidOperation instead of returning False. (Comparisons
+ involving a quiet NaN are unchanged.)
+
- Issue #2531: Comparison operations between floats and Decimal
instances now return a result based on the numeric values of the
operands; previously they returned an arbitrary result based on
More information about the Python-checkins
mailing list