簡體   English   中英

平方根Python 2.7.12

[英]Square root Python 2.7.12

為什么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

此處結果不正確。

為什么會這樣?

因為math.sqrt(..)首先將數字轉換為浮點,並且浮點的螳螂有限:它只能正確表示數字的一部分。 所以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

因此,信息在轉換為浮點數時已經丟失。

您可以在Wikipedia上有關IEEE-754的文章(關於浮點如何工作的正式定義)中了解更多有關浮點如何工作以及為什么它們是近似值的信息。

數學模塊文檔指出“它提供對C標准定義的數學函數的訪問”。 它還指出“除非另有明確說明,否則所有返回值都是浮點數”。

這些加在一起意味着平方根函數的參數是浮點值。 在大多數系統中,這意味着一個適合8個字節的浮點值,在C語言中稱為“雙精度”。 您的代碼會在計算平方根之前將整數值轉換為這樣的值,然后返回這樣的值。

但是,8字節浮點值最多可以存儲15到17個有效十進制數字 那就是您得到的結果。

如果要在平方根中獲得更高的精度,請使用保證為整數參數提供完全精度的函數。 只需進行網絡搜索,您就會發現幾個。 那些通常使用牛頓-拉夫森(Newton-Raphson)方法的變體來迭代並最終以正確的答案結束。 請注意,這比math模塊的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

如果要計算非常大的sympy數並且需要確切的結果,可以使用sympy

import sympy

num = sympy.Integer(123456758365483459347856)

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

浮點數存儲在內存中的方式進行計算時容易出現輕微的錯誤,但是在需要精確結果時卻可能非常重要。 如評論之一所述, decimal庫可以在這里為您提供幫助:

>>> A = Decimal(12345678917)
>>> A
Decimal('123456758365483459347856')
>>> B = A.sqrt()**2
>>> B
Decimal('123456758365483459347856.0000')
>>> A == B
True
>>> int(B)
123456758365483459347856

我使用版本3.6,它對整數的大小沒有硬編碼限制。 我不知道在2.7中將Bint是否會導致溢出,但是無論如何, decimal都是非常有用的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM