From a123631a5ca464c99faf039ee5c74ec9025d5d64 Mon Sep 17 00:00:00 2001 From: Mark Dickinson Date: Thu, 8 Jul 2010 19:03:34 +0000 Subject: [PATCH] Fix a performance issue in Decimal.pow. Thanks Stefan Krah for finding this. --- Lib/decimal.py | 14 ++++++++------ Lib/test/decimaltestdata/extra.decTest | 13 +++++++++++++ Misc/NEWS | 4 ++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/Lib/decimal.py b/Lib/decimal.py index 828027cd615..71408a8e9ed 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 2640842c68e..fce84355999 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 4ec9ec91437..369eaff885c 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.