【问题标题】:Exactness of integer square root in PythonPython中整数平方根的精确度
【发布时间】:2016-04-27 09:19:38
【问题描述】:

我想了解为什么会发生某些事情。我需要在 Python 中实现整数平方根 (iqrt(64) = 8 = isqrt(80))。我确信这种天真的方法:

def isqrt(n):
    return int(math.sqrt(n))

当传递的 n 是一个平方数时,肯定会偶尔失败,假设 Python 转换为浮点数,然后对浮点数执行平方根计算。例如,调用 isqrt(13*13) 我希望在转换为浮点数并计算 sqrt 之后,你会得到类似 12.999999843 的东西,在转换为整数后会得到 12。

但我执行了大循环测试值,无论大小,总是得到正确的结果。毕竟,似乎没有必要为整数实现特殊的平方根!

不理解让我感到困扰,就像本应有效的事情失败时一样。为什么会这样?

还有一个关于python中整数平方根的问题:Integer square root in python

在那里定义的 isqrt() 中,将 +0.5 添加到 n,我想这正是为了解决我提到的问题,但在特定情况下找不到。

编辑:忘了说明,我使用的是 Python 2.7

【问题讨论】:

  • 在 Python 2.7.6 中我得到math.sqrt(5) == 2.23606797749979,所以sqrt 结果总是浮点数,即使对于小整数参数也是如此。但我认为这在 Python 3 中发生了变化。Python 是动态类型的,因此原则上可以根据需要更改结果的类型 - 给出一个整数结果(包括大整数),其中参数是整数,如果这是决定的权力。这很有意义,但我没有检查过(因此评论没有回答)。
  • @Rogalski 我的问题是,为什么这(你的链接描述的)没有发生?
  • 在 CPython 2.7 中,math.sqrt() 被直接转发(除了复杂的数字处理魔法)到libm 中的相应函数(注意Decimal.sqrt() 不同)。毫不奇怪,pure C version 具有相同的行为

标签: python python-2.7 integer math.sqrt


【解决方案1】:

在 C 类型 long 作为 64 位整数和 C 类型 double 实现为 64 位 IEEE 浮点数的机器上使用 python 2.7 产生

>>> import math
>>> x = (2<<53) + 1
>>> int(math.sqrt(x*x)) == x
False

我作弊选择了一个 64 位 IEEE 浮点数不能精确表示的数字(但 python 的整数类型可以),(2&lt;&lt;53) + 1。 Python 2.7 将 x*x 计算为 python 2.7 long 整数。 (注意:这与 C long 不同;python 2.7 可以将 2&lt;&lt;600 表示为整数,但 C 不能。)

说到2&lt;&lt;600

>>> import math
>>> x = 2<<600
>>> int(math.sqrt(x*x)) == x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
OverflowError: long int too large to convert to float

【讨论】:

  • @Davin 很好的例子,你的测试远远超出了我的尝试。如果我理解,正在发生的事情是对于具有精确浮点数表示的平方数,平方根也是精确计算的。我不知道的事情!
  • FWIW,假设 IEEE 754 语义(C 的 double 匹配 IEEE 754 的 binary64),int(math.sqrt(n)) 没有给出正确结果的最小 nn = 2**52 + 2**27。跨度>
猜你喜欢
  • 1970-01-01
  • 2013-03-01
  • 2020-05-25
  • 1970-01-01
  • 2023-02-02
  • 2023-01-26
  • 1970-01-01
  • 1970-01-01
  • 2020-09-26
相关资源
最近更新 更多