2

在 Python 中,要么

n**0.5  # or
math.sqrt(n) 

当一个数字是一个完美的正方形时识别?具体来说,我应该担心当我使用

int(n**0.5)  # instead of
int(n**0.5 + 0.000000001)

由于精度误差,我可能会意外地得到比实际平方根小一号的结果?

4

6 回答 6

5

由于有几个答案建议使用整数算术,我会推荐gmpy2库。它提供了检查数字是否为完美幂、计算整数平方根和整数平方根余数的功能。

>>> import gmpy2
>>> gmpy2.is_power(9)
True
>>> gmpy2.is_power(10)
False
>>> gmpy2.isqrt(10)
mpz(3)
>>> gmpy2.isqrt_rem(10)
(mpz(3), mpz(1))

免责声明:我维护 gmpy2。

于 2013-06-06T19:48:18.113 回答
4

是的,你应该担心:

In [11]: int((100000000000000000000000000000000000**2) ** 0.5)
Out[11]: 99999999999999996863366107917975552L

In [12]: int(math.sqrt(100000000000000000000000000000000000**2))
Out[12]: 99999999999999996863366107917975552L

显然在0.000000001这里添加也无济于事......

正如@DSM 指出的那样,您可以使用十进制库:

In [21]: from decimal import Decimal

In [22]: x = Decimal('100000000000000000000000000000000000')

In [23]: (x ** 2).sqrt() == x
Out[23]: True

对于超过 的数字10**999999999,只要您检查精度(可配置),它会抛出错误而不是错误答案......

于 2013-06-06T18:43:24.510 回答
3

两者都**0.5使用math.sqrt()浮点运算执行计算。在计算平方根之前将输入转换为浮点数。

这些计算是否能识别输入值何时是一个完美的正方形?

不,他们没有。浮点算术没有完美平方的概念。

对于数字的有效数字多于浮点尾数中可用的数字的值,可能无法表示大整数。因此很容易看出,对于不可表示的输入值,n**0.5可能是不准确的。而且您通过添加一个小值提出的修复通常不会解决问题。

如果您的输入是整数,那么您应该考虑使用整数算术执行计算。这最终是处理这个问题的正确方法。

于 2013-06-06T18:41:59.343 回答
1

您可以在转换为 int 之前使用 round(number, Significant_figures),我不记得在进行浮点到整数转换时是否 python 截断或舍入。

无论如何,由于 python 使用浮点运算,所有的陷阱都适用。请参阅:
http ://docs.python.org/2/tutorial/floatingpoint.html

于 2013-06-06T18:44:06.407 回答
1

完全平方值将没有小数部分,因此您主要担心的是非常大的值,对于这样的值,1 或 2 的差异很重要意味着您将需要一个支持如此高精度的特定数值库(如DSM 提到,Decimal自 Python 2.4 以来的标准库应该能够做你想做的事情,因为它支持任意精度。

http://docs.python.org/library/decimal.html

于 2013-06-06T18:50:25.577 回答
1

sqrt是更容易实现的数学库函数之一,任何质量合理的数学库都将以忠实的舍入(亚 ULP 精度)来实现它。如果输入是一个完美的平方,它的平方根是可表示的(以合理的浮点格式)。在这种情况下,忠实的舍入保证结果是准确的。

这仅处理实际传递给的值sqrt。是否可以将数字从另一种格式无错误地转换为浮点输入sqrt是一个单独的问题。

于 2013-06-06T20:43:43.167 回答