8

我試圖寫一個函數來近似平方根(我知道有數學模塊...我想自己做),並且我被浮點算術搞砸了。你怎麼能避免這種情況?如何避免浮點錯誤?

def sqrt(num): 
    root = 0.0 
    while root * root < num: 
     root += 0.01 
    return root 

使用這有以下結果:

>>> sqrt(4) 
2.0000000000000013 
>>> sqrt(9) 
3.00999999999998 

我知道我可以只使用round(),但我希望能夠讓這個真正準確。我希望能夠計算出6位或7位數字。如果我四捨五入,這是不可能的。我想了解如何在Python中正確處理浮點計算。

+0

也許嘗試[小數](http://docs.python.org/2/library/decimal.html)模塊,這是精確設計? – Michael0x2a

回答

15

這實際上與Python沒有任何關係 - 使用硬件的二進制浮點算法,您會在任何語言中看到相同的行爲。第一個read the docs

讀完之後,你會更好地理解你是而不是在你的代碼中增加了百分之一。這是您要添加什麼:

>>> from decimal import Decimal 
>>> Decimal(.01) 
Decimal('0.01000000000000000020816681711721685132943093776702880859375') 

該字符串表示的二進制浮點(在C「雙精度」)的精確十進制值近似準確的十進制值0.01。你真的添加的東西比1/100大一點。

控制浮點數字錯誤是被稱爲「數值分析」的字段,是一個非常龐大而複雜的話題。只要您對浮點數只是十進制值的近似值而感到驚訝,請使用decimal模塊。這會爲你帶來一個「淺」問題的世界。例如,給定這個小修改你的函數:

from decimal import Decimal as D 

def sqrt(num): 
    root = D(0) 
    while root * root < num: 
     root += D("0.01") 
    return root 

則:

>>> sqrt(4) 
Decimal('2.00') 
>>> sqrt(9) 
Decimal('3.00') 

這不是真的更準確,但可能是簡單的例子那麼令人驚訝,因爲現在它的加入正好一一-hundredth。

另一種方法是堅持浮動並添加的東西可以完全表示爲二進制浮點形式:值爲I/2**J。例如,不要添加0.01,而要添加0.125(1/8)或0.0625(1/16)。

然後查找「牛頓法」,用於計算平方根;-)

+0

爲了記錄我讀過文檔,我確實已經知道存儲二進制表示的整個浮點精度。我忘記了牛頓的方法。你在這裏撿起我所有的問題!我發現你的幸運日。我不知道Decimal模塊是如何工作的。除了閱讀源代碼之外,還有什麼方法可以找到答案? – Aerovistae

+1

好吧,'decimal'最初是用Python編寫的,它處理十進制數字(0,1,2,...,9)的列表。非常模仿我們如何在紙上做算術! 「浮點」只需要向表示添加一個(十進制)指數,然後非常小心;-)當前的「十進制」模塊用C編碼,並且更加模糊:-( –

+0

如您所說,我嘗試過使用十進制模塊來解決'4 - 3.2'。 一個十進制=(4) B =十進制(3.2) 但 一個 - B結果爲小數( '0.7999999999999998223643160600') – Srinesh