mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Issue #7279: Make comparisons involving a Decimal sNaN signal InvalidOperation.
This commit is contained in:
		
							parent
							
								
									ea2d389474
								
							
						
					
					
						commit
						e096e82e82
					
				
					 3 changed files with 60 additions and 14 deletions
				
			
		|  | @ -845,8 +845,11 @@ def _cmp(self, other): | |||
|     # 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 @@ def _cmp(self, other): | |||
|     # 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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -26,6 +26,7 @@ | |||
| 
 | ||||
| import math | ||||
| import os, sys | ||||
| import operator | ||||
| import pickle, copy | ||||
| import unittest | ||||
| from decimal import * | ||||
|  | @ -1080,18 +1081,56 @@ def test_unary_operators(self): | |||
|         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)) | ||||
|  |  | |||
|  | @ -35,6 +35,10 @@ Core and Builtins | |||
| 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 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Mark Dickinson
						Mark Dickinson