From 9050bb28f2d73a1be8d568aea2b2eb9f53b90468 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Thu, 29 Oct 2009 12:25:07 +0000 Subject: Merged revisions 75947 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k ................ r75947 | mark.dickinson | 2009-10-29 12:23:02 +0000 (Thu, 29 Oct 2009) | 20 lines Merged revisions 75943-75945 via svnmerge from svn+ssh://pythondev@svn.python.org/python/trunk ........ r75943 | mark.dickinson | 2009-10-29 11:09:09 +0000 (Thu, 29 Oct 2009) | 1 line Fix duplicate test numbers in extra.decTest ........ r75944 | mark.dickinson | 2009-10-29 12:04:00 +0000 (Thu, 29 Oct 2009) | 3 lines Issue #7233: A number of two-argument Decimal methods were failing to accept ints and longs for the second argument. ........ r75945 | mark.dickinson | 2009-10-29 12:11:18 +0000 (Thu, 29 Oct 2009) | 4 lines Issue #7233: Fix Decimal.shift and Decimal.rotate methods for arguments with more digits than the current context precision. Bug reported by Stefan Krah. ........ ................ --- Lib/decimal.py | 39 +++++++++++++++++----- Lib/test/decimaltestdata/extra.decTest | 60 +++++++++++++++++++++++++--------- Lib/test/test_decimal.py | 47 ++++++++++++++++++++++++++ Misc/NEWS | 5 +++ 4 files changed, 126 insertions(+), 25 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py index b44c3f5..3450066 100644 --- a/Lib/decimal.py +++ b/Lib/decimal.py @@ -2806,6 +2806,8 @@ class Decimal(object): value. Note that a total ordering is defined for all possible abstract representations. """ + other = _convert_other(other, raiseit=True) + # if one is negative and the other is positive, it's easy if self._sign and not other._sign: return _NegativeOne @@ -2875,6 +2877,8 @@ class Decimal(object): Like compare_total, but with operand's sign ignored and assumed to be 0. """ + other = _convert_other(other, raiseit=True) + s = self.copy_abs() o = other.copy_abs() return s.compare_total(o) @@ -3243,6 +3247,9 @@ class Decimal(object): """Applies an 'and' operation between self and other's digits.""" if context is None: context = getcontext() + + other = _convert_other(other, raiseit=True) + if not self._islogical() or not other._islogical(): return context._raise_error(InvalidOperation) @@ -3264,6 +3271,9 @@ class Decimal(object): """Applies an 'or' operation between self and other's digits.""" if context is None: context = getcontext() + + other = _convert_other(other, raiseit=True) + if not self._islogical() or not other._islogical(): return context._raise_error(InvalidOperation) @@ -3278,6 +3288,9 @@ class Decimal(object): """Applies an 'xor' operation between self and other's digits.""" if context is None: context = getcontext() + + other = _convert_other(other, raiseit=True) + if not self._islogical() or not other._islogical(): return context._raise_error(InvalidOperation) @@ -3491,6 +3504,8 @@ class Decimal(object): if context is None: context = getcontext() + other = _convert_other(other, raiseit=True) + ans = self._check_nans(other, context) if ans: return ans @@ -3507,19 +3522,23 @@ class Decimal(object): torot = int(other) rotdig = self._int topad = context.prec - len(rotdig) - if topad: + if topad > 0: rotdig = '0'*topad + rotdig + elif topad < 0: + rotdig = rotdig[-topad:] # let's rotate! rotated = rotdig[torot:] + rotdig[:torot] return _dec_from_triple(self._sign, rotated.lstrip('0') or '0', self._exp) - def scaleb (self, other, context=None): + def scaleb(self, other, context=None): """Returns self operand after adding the second value to its exp.""" if context is None: context = getcontext() + other = _convert_other(other, raiseit=True) + ans = self._check_nans(other, context) if ans: return ans @@ -3543,6 +3562,8 @@ class Decimal(object): if context is None: context = getcontext() + other = _convert_other(other, raiseit=True) + ans = self._check_nans(other, context) if ans: return ans @@ -3557,22 +3578,22 @@ class Decimal(object): # get values, pad if necessary torot = int(other) - if not torot: - return Decimal(self) rotdig = self._int topad = context.prec - len(rotdig) - if topad: + if topad > 0: rotdig = '0'*topad + rotdig + elif topad < 0: + rotdig = rotdig[-topad:] # let's shift! if torot < 0: - rotated = rotdig[:torot] + shifted = rotdig[:torot] else: - rotated = rotdig + '0'*torot - rotated = rotated[-context.prec:] + shifted = rotdig + '0'*torot + shifted = shifted[-context.prec:] return _dec_from_triple(self._sign, - rotated.lstrip('0') or '0', self._exp) + shifted.lstrip('0') or '0', self._exp) # Support for pickling, copy, and deepcopy def __reduce__(self): diff --git a/Lib/test/decimaltestdata/extra.decTest b/Lib/test/decimaltestdata/extra.decTest index 15c1b52..2640842 100644 --- a/Lib/test/decimaltestdata/extra.decTest +++ b/Lib/test/decimaltestdata/extra.decTest @@ -154,22 +154,6 @@ extr1301 fma Inf 0 sNaN456 -> NaN Invalid_operation extr1302 fma 0E123 -Inf sNaN789 -> NaN Invalid_operation extr1302 fma -Inf 0E-456 sNaN148 -> NaN Invalid_operation --- Issue #6794: when comparing NaNs using compare_total, payloads --- should be compared as though positive integers; not --- lexicographically as strings. -extr1400 comparetotal NaN123 NaN45 -> 1 -extr1401 comparetotal sNaN123 sNaN45 -> 1 -extr1402 comparetotal -NaN123 -NaN45 -> -1 -extr1403 comparetotal -sNaN123 -sNaN45 -> -1 -extr1404 comparetotal NaN45 NaN123 -> -1 -extr1405 comparetotal sNaN45 sNaN123 -> -1 -extr1406 comparetotal -NaN45 -NaN123 -> 1 -extr1407 comparetotal -sNaN45 -sNaN123 -> 1 - -extr1410 comparetotal -sNaN63450748854172416 -sNaN911993 -> -1 -extr1411 comparetotmag NaN1222222222222 -NaN999999 -> 1 - - -- max/min/max_mag/min_mag bug in 2.5.2/2.6/3.0: max(NaN, finite) gave -- incorrect answers when the finite number required rounding; similarly -- for the other thre functions @@ -187,6 +171,50 @@ extr1421 max_mag NaN999999999 0.001234567 -> 0.00123457 Inexact Rounded extr1430 min_mag 9181716151 -NaN -> 9.18172E+9 Inexact Rounded extr1431 min_mag NaN4 1.818180E100 -> 1.81818E+100 Rounded +-- Issue #6794: when comparing NaNs using compare_total, payloads +-- should be compared as though positive integers; not +-- lexicographically as strings. +extr1500 comparetotal NaN123 NaN45 -> 1 +extr1501 comparetotal sNaN123 sNaN45 -> 1 +extr1502 comparetotal -NaN123 -NaN45 -> -1 +extr1503 comparetotal -sNaN123 -sNaN45 -> -1 +extr1504 comparetotal NaN45 NaN123 -> -1 +extr1505 comparetotal sNaN45 sNaN123 -> -1 +extr1506 comparetotal -NaN45 -NaN123 -> 1 +extr1507 comparetotal -sNaN45 -sNaN123 -> 1 + +extr1510 comparetotal -sNaN63450748854172416 -sNaN911993 -> -1 +extr1511 comparetotmag NaN1222222222222 -NaN999999 -> 1 + +-- Issue #7233: rotate and scale should truncate an argument +-- of length greater than the current precision. +precision: 4 +extr1600 rotate 1234567 -5 -> NaN Invalid_operation +extr1601 rotate 1234567 -4 -> 4567 +extr1602 rotate 1234567 -3 -> 5674 +extr1603 rotate 1234567 -2 -> 6745 +extr1604 rotate 1234567 -1 -> 7456 +extr1605 rotate 1234567 0 -> 4567 +extr1606 rotate 1234567 1 -> 5674 +extr1607 rotate 1234567 2 -> 6745 +extr1608 rotate 1234567 3 -> 7456 +extr1609 rotate 1234567 4 -> 4567 +extr1610 rotate 1234567 5 -> NaN Invalid_operation + +extr1650 shift 1234567 -5 -> NaN Invalid_operation +extr1651 shift 1234567 -4 -> 0 +extr1652 shift 1234567 -3 -> 4 +extr1653 shift 1234567 -2 -> 45 +extr1654 shift 1234567 -1 -> 456 +extr1655 shift 1234567 0 -> 4567 +extr1656 shift 1234567 1 -> 5670 +extr1657 shift 1234567 2 -> 6700 +extr1658 shift 1234567 3 -> 7000 +extr1659 shift 1234567 4 -> 0 +extr1660 shift 1234567 5 -> NaN Invalid_operation + + + -- Tests for the is_* boolean operations precision: 9 maxExponent: 999 diff --git a/Lib/test/test_decimal.py b/Lib/test/test_decimal.py index 4bf9d3a..bf7d3b2 100644 --- a/Lib/test/test_decimal.py +++ b/Lib/test/test_decimal.py @@ -1529,6 +1529,53 @@ class DecimalUsabilityTest(unittest.TestCase): self.assertEqual(str(Decimal(0).sqrt()), str(c.sqrt(Decimal(0)))) + def test_conversions_from_int(self): + # Check that methods taking a second Decimal argument will + # always accept an integer in place of a Decimal. + self.assertEqual(Decimal(4).compare(3), + Decimal(4).compare(Decimal(3))) + self.assertEqual(Decimal(4).compare_signal(3), + Decimal(4).compare_signal(Decimal(3))) + self.assertEqual(Decimal(4).compare_total(3), + Decimal(4).compare_total(Decimal(3))) + self.assertEqual(Decimal(4).compare_total_mag(3), + Decimal(4).compare_total_mag(Decimal(3))) + self.assertEqual(Decimal(10101).logical_and(1001), + Decimal(10101).logical_and(Decimal(1001))) + self.assertEqual(Decimal(10101).logical_or(1001), + Decimal(10101).logical_or(Decimal(1001))) + self.assertEqual(Decimal(10101).logical_xor(1001), + Decimal(10101).logical_xor(Decimal(1001))) + self.assertEqual(Decimal(567).max(123), + Decimal(567).max(Decimal(123))) + self.assertEqual(Decimal(567).max_mag(123), + Decimal(567).max_mag(Decimal(123))) + self.assertEqual(Decimal(567).min(123), + Decimal(567).min(Decimal(123))) + self.assertEqual(Decimal(567).min_mag(123), + Decimal(567).min_mag(Decimal(123))) + self.assertEqual(Decimal(567).next_toward(123), + Decimal(567).next_toward(Decimal(123))) + self.assertEqual(Decimal(1234).quantize(100), + Decimal(1234).quantize(Decimal(100))) + self.assertEqual(Decimal(768).remainder_near(1234), + Decimal(768).remainder_near(Decimal(1234))) + self.assertEqual(Decimal(123).rotate(1), + Decimal(123).rotate(Decimal(1))) + self.assertEqual(Decimal(1234).same_quantum(1000), + Decimal(1234).same_quantum(Decimal(1000))) + self.assertEqual(Decimal('9.123').scaleb(-100), + Decimal('9.123').scaleb(Decimal(-100))) + self.assertEqual(Decimal(456).shift(-1), + Decimal(456).shift(Decimal(-1))) + + self.assertEqual(Decimal(-12).fma(Decimal(45), 67), + Decimal(-12).fma(Decimal(45), Decimal(67))) + self.assertEqual(Decimal(-12).fma(45, 67), + Decimal(-12).fma(Decimal(45), Decimal(67))) + self.assertEqual(Decimal(-12).fma(45, Decimal(67)), + Decimal(-12).fma(Decimal(45), Decimal(67))) + class DecimalPythonAPItests(unittest.TestCase): diff --git a/Misc/NEWS b/Misc/NEWS index f63991f..c5ad099 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -37,6 +37,11 @@ Core and Builtins Library ------- +- Issue #7233: Fix a number of two-argument Decimal methods to make + sure that they accept an int or long as the second argument. Also + fix buggy handling of large arguments (those with coefficient longer + than the current precision) in shift and rotate. + - Issue #7205: Fix a possible deadlock when using a BZ2File object from several threads at once. -- cgit v0.12