summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2010-07-08 19:03:34 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2010-07-08 19:03:34 (GMT)
commita123631a5ca464c99faf039ee5c74ec9025d5d64 (patch)
tree93f70adf2ec66d91d1377eeea682eef31e60017a
parentf48ea7c2a950c81b98c6e689fc51c99598546bb4 (diff)
downloadcpython-a123631a5ca464c99faf039ee5c74ec9025d5d64.zip
cpython-a123631a5ca464c99faf039ee5c74ec9025d5d64.tar.gz
cpython-a123631a5ca464c99faf039ee5c74ec9025d5d64.tar.bz2
Fix a performance issue in Decimal.pow. Thanks Stefan Krah for finding this.
-rw-r--r--Lib/decimal.py14
-rw-r--r--Lib/test/decimaltestdata/extra.decTest13
-rw-r--r--Misc/NEWS4
3 files changed, 25 insertions, 6 deletions
diff --git a/Lib/decimal.py b/Lib/decimal.py
index 828027c..71408a8 100644
--- a/Lib/decimal.py
+++ b/Lib/decimal.py
@@ -2047,12 +2047,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
diff --git a/Lib/test/decimaltestdata/extra.decTest b/Lib/test/decimaltestdata/extra.decTest
index 2640842..fce8435 100644
--- a/Lib/test/decimaltestdata/extra.decTest
+++ b/Lib/test/decimaltestdata/extra.decTest
@@ -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
diff --git a/Misc/NEWS b/Misc/NEWS
index 4ec9ec9..369eaff 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -470,6 +470,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 #9186: Fix math.log1p(-1.0) to raise ValueError, not OverflowError.
- Issue #9130: Fix validation of relative imports in parser module.