平方根Python 2.7.12

时间:2017-01-09 15:39:16

标签: python math sqrt

为什么math模块返回错误的结果?

首次测试

A = 12345678917
print 'A =',A
B = sqrt(A**2)
print 'B =',int(B)

结果

A = 12345678917
B = 12345678917

这里,结果是正确的。

第二次测试

A = 123456758365483459347856
print 'A =',A
B = sqrt(A**2)
print 'B =',int(B)

结果

A = 123456758365483459347856
B = 123456758365483467538432

此处结果不正确。

为什么会这样?

4 个答案:

答案 0 :(得分:4)

因为math.sqrt(..)首先将数字转换为浮点并且浮点数具有有限的 mantisse :它只能正确表示数字的一部分。因此float(A**2)不等于A**2。接下来,它会计算math.sqrt,这也是近似正确的。

使用浮点的大多数函数永远不会完全正确对应它们的整数对应物。浮点计算几乎具有近似性。

如果计算A**2,则得到:

>>> 12345678917**2
152415787921658292889L

现在,如果将其转换为float(..),则会获得:

>>> float(12345678917**2)
1.5241578792165828e+20

但如果你现在问两者是否相等:

>>> float(12345678917**2) == 12345678917**2
False

因此,在将其转换为浮动信息时,信息已丢失。

您可以在维基百科关于IEEE-754的文章中详细了解浮点数的工作原理以及这些浮点数的近似值,这是关于浮点数如何运作的正式定义。

答案 1 :(得分:4)

documentation for the math module状态"它提供对C标准定义的数学函数的访问。"它还声明"除非另有明确说明,否则所有返回值都是浮点数。"

这些一起意味着平方根函数的参数是浮点值。在大多数系统中,这意味着一个适合8个字节的浮点值,称为" double"在C语言中。您的代码在计算平方根之前将整数值转换为这样的值,然后返回这样的值。

但是,8字节浮点值可以存储at most 15 to 17 significant decimal digits。这就是你在结果中得到的结果。

如果要在平方根中获得更好的精度,请使用保证为整数参数提供完全精度的函数。只需进行网络搜索,您就会找到几个。那些人通常会使用Newton-Raphson方法的变体来迭代并最终以正确的答案结束。请注意,这比数学模块的sqrt函数慢得多。

这是我从互联网上修改过的例程。我现在无法引用消息来源。此版本也适用于非整数参数,但只返回平方根的整数部分。

def isqrt(x):
    """Return the integer part of the square root of x, even for very
    large values."""
    if x < 0:
        raise ValueError('square root not defined for negative numbers')
    n = int(x)
    if n == 0:
        return 0
    a, b = divmod(n.bit_length(), 2)
    x = (1 << (a+b)) - 1
    while True:
        y = (x + n//x) // 2
        if y >= x:
            return x
        x = y

答案 2 :(得分:2)

如果您想计算真正大数字的sqrt并且需要精确结果,可以使用sympy

import sympy

num = sympy.Integer(123456758365483459347856)

print(int(num) == int(sympy.sqrt(num**2)))

答案 3 :(得分:0)

浮点数存储在内存中的方式使得它们的计算容易出现轻微错误,但在需要精确结果时仍然很重要。正如其中一条评论中所述,?库可以在这里为您提供帮助:

decimal

我使用版本3.6,它对整数的大小没有硬编码限制。我不知道,在2.7中,将>>> A = Decimal(12345678917) >>> A Decimal('123456758365483459347856') >>> B = A.sqrt()**2 >>> B Decimal('123456758365483459347856.0000') >>> A == B True >>> int(B) 123456758365483459347856 视为B会导致溢出,但int无论如何都非常有用。