【问题标题】:Python sqrt limit for very large numbers?非常大的数字的Python sqrt限制?
【发布时间】:2015-01-30 16:08:53
【问题描述】:

我正在处理非常大的数字(1,000,000 位),我需要计算它们的平方根。我的代码似乎遇到了限制。

y = 10**309
x = y**0.5
print(x)

我收到了这个错误:

x = y**0.5
OverflowError: int too large to convert to float

代码工作到 10**308。但除此之外,它似乎坏了。我也在命令行中检查了这一点。同样的错误。有人可以帮帮我吗?

如果这是 Python 的限制,我可以使用其他方法吗?

【问题讨论】:

  • 有趣的是,math.sqrt 返回inf 用于大于 10^308 的任何值
  • 我认为如果没有当前的数学水平应该是可行的......但我没有什么希望......甚至更少希望已经存在某些东西(即使在数学水平......不是编程)为您提供帮助。
  • 您可以简化问题:将您的数字除以例如10^100。 10^100 的平方根 = 10^50。然后你可以使用 sqrt(a*b) = sqrt(a) * sqrt(b)。
  • @AlexMartelli,对我系统的快速测试表明,gmpy2.isqrt 可以在不到 25 毫秒的时间内计算出 1,000,0000 位数字的整数平方根。
  • 结果准确。您确实需要使用正确的功能。 isqrt 计算整数平方根。 sqrt 返回一个多精度浮点值,但您可以将精度提高到任意位数。

标签: python square-root sqrt


【解决方案1】:

用一点数学来简化你的问题。

注意sqrt(a*b) = sqrt(a) * sqrt(b)(至少是实数,正数)。

因此,任何大于 10^100 的数除以 10^100。那就是a,除法的结果是b,所以你原来的数=a * b。 然后使用 10^100 (= 10^50) 的平方根,乘以 b 的平方根,你就有了答案。

用你的例子:

import math
x = 10**309
a = 1e100
b = 1e209   # Note: you can't calculate this within Python; just use plain math here
y = 1e50 * math.sqrt(1e209)

非整数的例子:

x = 3.1415 * 1e309
a = 1e100
b = 3.1415e209   # Again, just subtract the exponent: 309 - 100
y = 1e50 * math.sqrt(3.1415e209)

或者对于一个不是 10 的幂的整数,完全写出:

x = 707070
x = 70.707 * 1e4  # note: even number in exponent
x = 70.707e4
a = 1e2  # sqrt(1e2) = 1e1 = 10
b = 70.707e2
y = 10 * sqrt(70.707e2)

几点说明:

  • Python 可以毫无问题地处理非常大的 整数 数字。对于浮点数,它使用标准 (C) 约定,并将自身限制为 64 位精度。在取某事物的平方根时,您几乎总是得到浮点数。

  • 1e309 表示10**3093.1415e209 表示3.1415 * 10**209。这是标准的编程约定。

【讨论】:

  • 我很高兴你修改了你的初稿,我没能及时要求 :-)
  • 嗨@Evert,谢谢你的想法......但10 ^ 309只是上限示例。我正在处理所有整数,而不仅仅是 10、100 或 1000。所以这个解决方案虽然优雅,但对我不起作用。不过还是谢谢你。感谢您抽出宝贵时间回答:)
  • @SAnwa​​r 如果您没有得到第二个示例(它只是一个不是 10 的幂的大整数),我添加了另一个可能更清楚的示例。
【解决方案2】:

您应该使用gmpy2 module。它提供了非常快速的多精度算术。

在我的系统上,百万位数的运算速度非常快。

In [8]: a=gmpy2.mpz('3'*1000000)

In [9]: %timeit gmpy2.isqrt(a)
10 loops, best of 3: 22.8 ms per loop

In [10]: %timeit (a+1)*(a-1)
10 loops, best of 3: 20.9 ms per loop

处理 100,000,000 个数字只需几秒钟。

In [20]: a.num_digits(10)
Out[20]: 99995229

In [21]: %timeit gmpy2.isqrt(a)
1 loops, best of 3: 5.05 s per loop

In [22]: %timeit (a+1)*(a-1)
1 loops, best of 3: 3.49 s per loop

免责声明:我是gmpy2 的当前维护者。

【讨论】:

    【解决方案3】:

    根据我认为的similar questions,您可以考虑使用Decimal class

    这是一个使用你所拥有的示例

    >>> x = 10**309
    >>> y =x**.5
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    OverflowError: long int too large to convert to float
    >>> import decimal
    >>> d = decimal.Decimal(x)
    >>> d.sqrt()
    Decimal('3.162277660168379331998893544E+154')
    >>> float(d.sqrt())
    3.1622776601683792e+154
    

    可能会有所帮助,它不会给您带来错误。

    【讨论】:

    • 不...目前的数学水平对此没有答案。
    • 更多地指的是他的具体例子。一般来说,我不同意有些数字对于当前计算来说太大了。我将添加一个编辑。
    • @CSCFCEM,有一些数字太大而无法舒适地放入内存中(包括处理它们的中间结果所需的空间),但是根据您的 RAM 数量,有数百万到几个十亿位数字,而不是数百位! “当前数学水平”非常好 - 只需安装 gmpy2 并购买 更多 更多 RAM!-)
    • 我同意@AlexMartelli。如果我说了一些让我听起来不同意的话,我会很乐意纠正它。
    • @CSCFCEM,鉴于 Sarvesh 对“当前数学水平”的评论(?!),“我不同意有些数字对于当前计算来说太大了”,这听起来是您不同意的地方。当然,用于数字的许多特定格式(例如float)都有特定限制(通常由硬件强加,而不是由“当前数学”或“当前计算”!-),但简单的解决方案是,只需使用不同的格式(当前的数学完全支持当前的计算——只要你购买足够的 RAM :-)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 2015-02-15
    • 1970-01-01
    • 2020-07-16
    相关资源
    最近更新 更多