]> granicus.if.org Git - python/commitdiff
Merged revisions 82646,82649-82650 via svnmerge from
authorMark Dickinson <dickinsm@gmail.com>
Thu, 8 Jul 2010 19:21:59 +0000 (19:21 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Thu, 8 Jul 2010 19:21:59 +0000 (19:21 +0000)
svn+ssh://pythondev@svn.python.org/python/branches/py3k

........
  r82646 | mark.dickinson | 2010-07-08 18:23:40 +0100 (Thu, 08 Jul 2010) | 1 line

  In test_decimal, convert heuristic for skipping tests into an explicit skiplist.
........
  r82649 | mark.dickinson | 2010-07-08 20:03:34 +0100 (Thu, 08 Jul 2010) | 1 line

  Fix a performance issue in Decimal.pow.  Thanks Stefan Krah for finding this.
........
  r82650 | mark.dickinson | 2010-07-08 20:09:16 +0100 (Thu, 08 Jul 2010) | 1 line

  Fix misplaced exactness check that was causing unnecessary work in Decimal.__pow__.
........

Lib/decimal.py
Lib/test/decimaltestdata/extra.decTest
Lib/test/test_decimal.py
Misc/NEWS

index ecf0cd523e5d023f6ef7a902b0cab469739509e0..958b2f9a72bf512cd91544e9d1def95baf0c4c2c 100644 (file)
@@ -2044,12 +2044,14 @@ class Decimal(object):
         # case where xc == 1: result is 10**(xe*y), with xe*y
         # required to be an integer
         if xc == 1:
-            if ye >= 0:
-                exponent = xe*yc*10**ye
-            else:
-                exponent, remainder = divmod(xe*yc, 10**-ye)
-                if remainder:
-                    return None
+            xe *= yc
+            # result is now 10**(xe * 10**ye);  xe * 10**ye must be integral
+            while xe % 10 == 0:
+                xe //= 10
+                ye += 1
+            if ye < 0:
+                return None
+            exponent = xe * 10**ye
             if y.sign == 1:
                 exponent = -exponent
             # if other is a nonnegative integer, use ideal exponent
@@ -2322,9 +2324,10 @@ class Decimal(object):
         # try for an exact result with precision +1
         if ans is None:
             ans = self._power_exact(other, context.prec + 1)
-            if ans is not None and result_sign == 1:
-                ans = _dec_from_triple(1, ans._int, ans._exp)
-            exact = True
+            if ans is not None:
+                if result_sign == 1:
+                    ans = _dec_from_triple(1, ans._int, ans._exp)
+                exact = True
 
         # usual case: inexact result, x**y computed directly as exp(y*log(x))
         if ans is None:
index 2640842c68eb9b4e32a8f54317bcd040c1371caa..fce84355999163a9c0b7af639dda1069ee6d7492 100644 (file)
@@ -213,7 +213,20 @@ extr1658 shift 1234567 3 -> 7000
 extr1659 shift 1234567 4 -> 0
 extr1660 shift 1234567 5 -> NaN Invalid_operation
 
+-- Cases where the power function was impossibly slow to determine that the
+-- result is inexact.  Thanks Stefan Krah for identifying this problem.
+precision: 16
+maxExponent: 999999999
+minExponent: -999999999
+extr1700 power 10 1e-999999999 -> 1.000000000000000 Inexact Rounded
+extr1701 power 100.0 -557.71e-742888888 -> 1.000000000000000 Inexact Rounded
+extr1702 power 10 1e-100 -> 1.000000000000000 Inexact Rounded
 
+-- A couple of interesting exact cases for power.  Note that the specification
+-- requires these to be reported as Inexact.
+extr1710 power 1e375 56e-3 -> 1.000000000000000E+21 Inexact Rounded
+extr1711 power 10000 0.75 -> 1000.000000000000 Inexact Rounded
+extr1712 power 1e-24 0.875 -> 1.000000000000000E-21 Inexact Rounded
 
 -- Tests for the is_* boolean operations
 precision: 9
index dad63aee31332a777833e56ce6ff102504ae818f..e9fbad44ca8e29aaea10d2c09bb245c574e7f225 100644 (file)
@@ -71,10 +71,41 @@ skip_expected = not os.path.isdir(directory)
 
 # list of individual .decTest test ids that correspond to tests that
 # we're skipping for one reason or another.
-skipped_test_ids = [
-    'scbx164',  # skipping apparently implementation-specific scaleb
-    'scbx165',  # tests, pending clarification of scaleb rules.
-]
+skipped_test_ids = set([
+    # Skip implementation-specific scaleb tests.
+    'scbx164',
+    'scbx165',
+
+    # For some operations (currently exp, ln, log10, power), the decNumber
+    # reference implementation imposes additional restrictions on the context
+    # and operands.  These restrictions are not part of the specification;
+    # however, the effect of these restrictions does show up in some of the
+    # testcases.  We skip testcases that violate these restrictions, since
+    # Decimal behaves differently from decNumber for these testcases so these
+    # testcases would otherwise fail.
+    'expx901',
+    'expx902',
+    'expx903',
+    'expx905',
+    'lnx901',
+    'lnx902',
+    'lnx903',
+    'lnx905',
+    'logx901',
+    'logx902',
+    'logx903',
+    'logx905',
+    'powx1183',
+    'powx1184',
+    'powx4001',
+    'powx4002',
+    'powx4003',
+    'powx4005',
+    'powx4008',
+    'powx4010',
+    'powx4012',
+    'powx4014',
+    ])
 
 # Make sure it actually raises errors when not expected and caught in flags
 # Slower, since it runs some things several times.
@@ -165,27 +196,6 @@ LOGICAL_FUNCTIONS = (
     'same_quantum',
     )
 
-# For some operations (currently exp, ln, log10, power), the decNumber
-# reference implementation imposes additional restrictions on the
-# context and operands.  These restrictions are not part of the
-# specification; however, the effect of these restrictions does show
-# up in some of the testcases.  We skip testcases that violate these
-# restrictions, since Decimal behaves differently from decNumber for
-# these testcases so these testcases would otherwise fail.
-
-decNumberRestricted = ('power', 'ln', 'log10', 'exp')
-DEC_MAX_MATH = 999999
-def outside_decNumber_bounds(v, context):
-    if (context.prec > DEC_MAX_MATH or
-        context.Emax > DEC_MAX_MATH or
-        -context.Emin > DEC_MAX_MATH):
-        return True
-    if not v._is_special and v and (
-        v.adjusted() > DEC_MAX_MATH or
-        v.adjusted() < 1-2*DEC_MAX_MATH):
-        return True
-    return False
-
 class DecimalTest(unittest.TestCase):
     """Class which tests the Decimal class against the test cases.
 
@@ -323,22 +333,6 @@ class DecimalTest(unittest.TestCase):
 
         ans = FixQuotes(ans)
 
-        # skip tests that are related to bounds imposed in the decNumber
-        # reference implementation
-        if fname in decNumberRestricted:
-            if fname == 'power':
-                if not (vals[1]._isinteger() and
-                        -1999999997 <= vals[1] <= 999999999):
-                    if outside_decNumber_bounds(vals[0], self.context) or \
-                            outside_decNumber_bounds(vals[1], self.context):
-                        #print "Skipping test %s" % s
-                        return
-            else:
-                if outside_decNumber_bounds(vals[0], self.context):
-                    #print "Skipping test %s" % s
-                    return
-
-
         if EXTENDEDERRORTEST and fname not in ('to_sci_string', 'to_eng_string'):
             for error in theirexceptions:
                 self.context.traps[error] = 1
index 87af41cdda923303a62347ff380147eacb7d9b26..a236f60b27b057c9629b45538a5b0a28e76c2c69 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -75,6 +75,10 @@ C-API
 Library
 -------
 
+- Fix extreme speed issue in Decimal.pow when the base is an exact
+  power of 10 and the exponent is tiny (for example,
+  Decimal(10) ** Decimal('1e-999999999')).
+
 - Issue #9130: Fix validation of relative imports in parser module.
 
 - Issue #9128: Fix validation of class decorators in parser module.