mirror of
https://github.com/python/cpython.git
synced 2025-12-11 11:31:05 +00:00
gh-118164: str(10**10000) hangs if the C _decimal module is missing (#118503)
* Initial stab. * Test the tentative fix. Hangs "forever" without this change. * Move the new test to a better spot. * New comment to explain why _convert_to_str allows any poewr of 10. * Fixed a comment, and fleshed out an existing test that appeared unfinished. * Added temporary asserts. Or maybe permanent ;-) * Update Lib/_pydecimal.py Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> * Remove the new _convert_to_str(). Serhiy and I independently concluded that exact powers of 10 aren't possible in these contexts, so just checking the string length is sufficient. * At least for now, add the asserts to the other block too. * 📜🤖 Added by blurb_it. --------- Co-authored-by: Serhiy Storchaka <storchaka@gmail.com> Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
This commit is contained in:
parent
08d169f14a
commit
999f0c5122
3 changed files with 40 additions and 5 deletions
|
|
@ -2131,10 +2131,16 @@ class Decimal(object):
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if xc >= 10**p:
|
# An exact power of 10 is representable, but can convert to a
|
||||||
|
# string of any length. But an exact power of 10 shouldn't be
|
||||||
|
# possible at this point.
|
||||||
|
assert xc > 1, self
|
||||||
|
assert xc % 10 != 0, self
|
||||||
|
strxc = str(xc)
|
||||||
|
if len(strxc) > p:
|
||||||
return None
|
return None
|
||||||
xe = -e-xe
|
xe = -e-xe
|
||||||
return _dec_from_triple(0, str(xc), xe)
|
return _dec_from_triple(0, strxc, xe)
|
||||||
|
|
||||||
# now y is positive; find m and n such that y = m/n
|
# now y is positive; find m and n such that y = m/n
|
||||||
if ye >= 0:
|
if ye >= 0:
|
||||||
|
|
@ -2184,13 +2190,18 @@ class Decimal(object):
|
||||||
return None
|
return None
|
||||||
xc = xc**m
|
xc = xc**m
|
||||||
xe *= m
|
xe *= m
|
||||||
if xc > 10**p:
|
# An exact power of 10 is representable, but can convert to a string
|
||||||
|
# of any length. But an exact power of 10 shouldn't be possible at
|
||||||
|
# this point.
|
||||||
|
assert xc > 1, self
|
||||||
|
assert xc % 10 != 0, self
|
||||||
|
str_xc = str(xc)
|
||||||
|
if len(str_xc) > p:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# by this point the result *is* exactly representable
|
# by this point the result *is* exactly representable
|
||||||
# adjust the exponent to get as close as possible to the ideal
|
# adjust the exponent to get as close as possible to the ideal
|
||||||
# exponent, if necessary
|
# exponent, if necessary
|
||||||
str_xc = str(xc)
|
|
||||||
if other._isinteger() and other._sign == 0:
|
if other._isinteger() and other._sign == 0:
|
||||||
ideal_exponent = self._exp*int(other)
|
ideal_exponent = self._exp*int(other)
|
||||||
zeros = min(xe-ideal_exponent, p-len(str_xc))
|
zeros = min(xe-ideal_exponent, p-len(str_xc))
|
||||||
|
|
|
||||||
|
|
@ -4716,9 +4716,33 @@ class PyWhitebox(unittest.TestCase):
|
||||||
|
|
||||||
c.prec = 1
|
c.prec = 1
|
||||||
x = Decimal("152587890625") ** Decimal('-0.5')
|
x = Decimal("152587890625") ** Decimal('-0.5')
|
||||||
|
self.assertEqual(x, Decimal('3e-6'))
|
||||||
|
c.prec = 2
|
||||||
|
x = Decimal("152587890625") ** Decimal('-0.5')
|
||||||
|
self.assertEqual(x, Decimal('2.6e-6'))
|
||||||
|
c.prec = 3
|
||||||
|
x = Decimal("152587890625") ** Decimal('-0.5')
|
||||||
|
self.assertEqual(x, Decimal('2.56e-6'))
|
||||||
|
c.prec = 28
|
||||||
|
x = Decimal("152587890625") ** Decimal('-0.5')
|
||||||
|
self.assertEqual(x, Decimal('2.56e-6'))
|
||||||
|
|
||||||
c.prec = 201
|
c.prec = 201
|
||||||
x = Decimal(2**578) ** Decimal("-0.5")
|
x = Decimal(2**578) ** Decimal("-0.5")
|
||||||
|
|
||||||
|
# See https://github.com/python/cpython/issues/118027
|
||||||
|
# Testing for an exact power could appear to hang, in the Python
|
||||||
|
# version, as it attempted to compute 10**(MAX_EMAX + 1).
|
||||||
|
# Fixed via https://github.com/python/cpython/pull/118503.
|
||||||
|
c.prec = P.MAX_PREC
|
||||||
|
c.Emax = P.MAX_EMAX
|
||||||
|
c.Emin = P.MIN_EMIN
|
||||||
|
c.traps[P.Inexact] = 1
|
||||||
|
D2 = Decimal(2)
|
||||||
|
# If the bug is still present, the next statement won't complete.
|
||||||
|
res = D2 ** 117
|
||||||
|
self.assertEqual(res, 1 << 117)
|
||||||
|
|
||||||
def test_py_immutability_operations(self):
|
def test_py_immutability_operations(self):
|
||||||
# Do operations and check that it didn't change internal objects.
|
# Do operations and check that it didn't change internal objects.
|
||||||
Decimal = P.Decimal
|
Decimal = P.Decimal
|
||||||
|
|
@ -5705,7 +5729,6 @@ class CWhitebox(unittest.TestCase):
|
||||||
with C.localcontext(rounding=C.ROUND_DOWN):
|
with C.localcontext(rounding=C.ROUND_DOWN):
|
||||||
self.assertEqual(format(y, '#.1f'), '6.0')
|
self.assertEqual(format(y, '#.1f'), '6.0')
|
||||||
|
|
||||||
|
|
||||||
@requires_docstrings
|
@requires_docstrings
|
||||||
@requires_cdecimal
|
@requires_cdecimal
|
||||||
class SignatureTest(unittest.TestCase):
|
class SignatureTest(unittest.TestCase):
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
The Python implementation of the ``decimal`` module could appear to hang in relatively small power cases (like ``2**117``) if context precision was set to a very high value. A different method to check for exactly representable results is used now that doesn't rely on computing ``10**precision`` (which could be effectively too large to compute).
|
||||||
Loading…
Add table
Add a link
Reference in a new issue