【问题标题】:square root of a number greater than 10^2000 in Python 3Python 3 中大于 10^2000 的数的平方根
【发布时间】:2018-05-30 23:30:46
【问题描述】:

我想在 Python 中计算大于 10^2000 的数字的平方根。如果我把这个数字当作一个普通的整数,我总会得到这个结果:

Traceback (most recent call last):
  File "...", line 3, in <module>
    print( q*(0.5)  )
OverflowError: int too large to convert to float

我该如何解决这个问题?或者是否存在使用 Python 以外的其他方法来计算这个平方根?

【问题讨论】:

  • 你的意思是10^2000还是10**2000

标签: python python-3.x large-data largenumber square-root


【解决方案1】:

只需使用十进制模块:

>>> from decimal import *
>>> Decimal(10**2000).sqrt()
Decimal('1.000000000000000000000000000E+1000')
>>> Decimal(10**200000).sqrt()
Decimal('1.000000000000000000000000000E+100000')
>>> Decimal(15**35315).sqrt()
Decimal('6.782765081358674922386659760E+20766')

您也可以使用gmpy2 library

>>> import gmpy2
>>> n = gmpy2.mpz(99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999982920000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000726067)
>>> gmpy2.get_context().precision=2048
>>> x = gmpy2.sqrt(n)

有用的链接:

  1. Decimal - Python Documentation

【讨论】:

  • ^ 运算符表示 Python 中的 XOR。你应该使用**。您也可以在错误的结果中看到这一点。
  • Java 中没有指数运算符。 10^2000 的平方根从不 44.83...
  • 如果你正在寻找一个整数结果并且打算使用gmpy2,最简单和最好的方法就是`gmpy2.isqrt()。
【解决方案2】:

通常的平方根方法在进行计算之前将参数转换为浮点值。如您所见,这不适用于非常大的整数。

因此,请使用旨在处理任意大整数的函数。这是一个,保证返回任何正整数的平方根的正确整数部分。此函数删除结果的小数部分,这可能是也可能不是您想要的。由于此函数使用迭代,它也比内置的平方根例程慢。 Decimal 模块适用于比内置例程更大的整数,但值的精度必须提前定义,因此它不适用于任意大的值。

import math

_1_50 = 1 << 50  # 2**50 == 1,125,899,906,842,624

def isqrt(x):
    """Return the integer part of the square root of x, even for very
    large integer values."""
    if x < 0:
        raise ValueError('square root not defined for negative numbers')
    if x < _1_50:
        return int(math.sqrt(x))  # use math's sqrt() for small parameters
    n = int(x)
    if n <= 1:
        return n  # handle sqrt(0)==0, sqrt(1)==1
    # Make a high initial estimate of the result (a little lower is slower!!!)
    r = 1 << ((n.bit_length() + 1) >> 1)
    while True:
        newr = (r + n // r) >> 1  # next estimate by Newton-Raphson
        if newr >= r:
            return r
        r = newr

【讨论】:

  • “保证返回任何正整数平方根的正确整数部分”——这似乎不适用于我的情况:isqrt(178533196125860586848256)=422531887702 != math.sqrt(178533196125860586848256)=422531887703。我的计算器也给出了 422531887703。我用 Python 3.5.2 x64 试了一下
  • @Dmitry:当我检查您的评论时,我发现我的isqrt 是正确的,而其他计算是错误的。通过在 Python 中评估 422531887702**2 &lt;= 178533196125860586848256 &lt; 422531887703**2,您可以看到我的方法是正确的。计算结果为True。但是,422531887703**2 &lt;= 178533196125860586848256 的计算结果为 False。如果其他方法说正确的平方根是422531887703,那么它们是错误的。请自行检查。如果您在我的代码中发现实际错误,我很想知道,所以请告诉我。
  • @RoryDaulton 感谢您的检查。是的,你是对的——你的实现给出了准确的整个部分,而 math.sqrt 对大数字表现得很奇怪:math.sqrt(178533196125860602616209) == math.sqrt(178533196125860586848256) 返回 True!
  • 据我所见,if n &lt;= 1 总是错误的,因为前面的if x &lt; _1_50: return int(math.sqrt(x))
  • @J.Win.:我的isqrt 返回的数字与您显示的数字不同。您的号码以903 结尾,而我的isqrt 返回的号码以003 结尾。其余数字一致。我的测试显示我的结果是正确的。请仔细检查您获得的结果以及您对结果的测试。
【解决方案3】:

当使用库 math 中的 sqrt 时,在对其进行平方根之前,它会将值转换为浮点数。

如果我们手动尝试将10**2000 转换为浮点数,也会触发错误

>>> float(10**2000)
---------------------------------------------------------------------------
OverflowError                             Traceback (most recent call last)
<ipython-input-14-6ac81f63106d> in <module>
----> 1 math.sqrt(10**2000)

OverflowError: int too large to convert to float

如果我们说的是一个大数,但平方等于或小于 308,Decimal 模块将按以下方式工作

>>> from decimal import Decimal
>>> Decimal(math.sqrt(10**308))
Decimal('10000000000000000369475456880582265409809179829842688451922778552150543659347219597216513109705408327446511753687232667314337003349573404171046192448274432')

但是,由于数字的平方远大于 308,在这种情况下为 2000,则必须执行以下操作

>>> from decimal import Decimal
>>> Decimal(10**2000).sqrt()
Decimal('1.000000000000000000000000000E+1000')

如果尝试将Decimal(10**2000) 转换为浮点数,让我们看看输出

>>> float(Decimal(10**2000))
inf

在处理阶乘时也可以使用小数模块,因为它们往往会很快变大。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-02-25
    • 1970-01-01
    • 2013-03-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-20
    • 1970-01-01
    相关资源
    最近更新 更多