[英]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
浮點數存儲在內存中的方式進行計算時容易出現輕微的錯誤,但是在需要精確結果時卻可能非常重要。 如評論之一所述, 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中將B
為int
是否會導致溢出,但是無論如何, decimal
都是非常有用的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.