2010-08-22 75 views
3

我是一個相當綠色的程序員,現在我正在學習Python。我到第17章中的「學會思考就像一個計算機科學家」(類和方法),我只是寫了失敗的方式我真的不完全我的第一個文檔測試理解:Python中數值的陷阱,「有多深?」

class Point(object): 
    ''' 
    represents a point object. 
    attributes: x, y 
    ''' 

    def ___init___(self, x = 0, y = 0): 
     ''' 
     >>> point = Point() 
     >>> point.y 
     0 
     >>> point = Point(4.7, 8.2) 
     >>> point.x 
     4.7 
     ''' 

     self.x = x 
     self.y = y 

的第二個doctest爲__init__失敗,並返回4.7000000000000002而不是4.7。但是,如果我用「打印」語句重寫doctest,如下所示:

>>> point = Point(4.7, 8.2) 
>>> print point.x 
4.7 

它運行正常。

所以我讀到了Python如何存儲浮動數據,現在我明白了,由於二進制表示的十進制數字,造成這種差異的原因是Python將4.7存儲爲1和0的字符串, t相當於4.7。

但我不明白的是爲什麼對「point.x」的調用返回4.7000000000000002,而對「print point.x」的調用返回4.7。在其他什麼情況下,Python會選擇像「打印」一樣輪流?這個四捨五入工作如何?這些尾隨的重要人物是否會導致編程錯誤(除了顯然是失敗的文檔之外)?一個不注意四捨五入的人會產生危險的歧義嗎?由於這與十進制數的二進制表示有關,我確定這實際上是一個通用的CS問題,而不是Python特有的問題,但我現在真正需要知道的是我可以做的,特別是作爲Python程序員,以避免任何相關問題和/或錯誤感染。

另外,對於獎勵積分,還有其他一些Python可以存儲浮點數的方式,除了像「a = 4.7」這樣的行激活的默認值嗎?我知道有Decimal包,但我不完全確定它是如何工作的。老實說,所有這些動態打字的東西有時讓我感到困惑。

編輯: 我應該指定,我使用的Python 2.6(在某些時候我想用與NumPy和Biopython)

+0

只要寫4.5:對 – kennytm 2010-08-22 16:19:45

+4

最近的Python版本(2.7和3.1)即使沒有「print」也會顯示4.7。基本的不準確(由於浮點不精確)仍然存在。 – interjay 2010-08-22 16:22:53

回答

1

你得到不同的行爲,因爲print截斷數字:

In [1]: 1.23456789
Out[1]: 1.23456789
In [2]: print 1.23456789
1.23456789012 

注意,在精度Python的彩車使用:

In [3]: 4.7 == 4.7000000000000002 
Out[3]: True 

釷是因爲浮點數have a limited (relative) precision,因爲它們使用有限數量的(二進制)數字來表示實數。因此,如上所述,給定數字的不同十進制表示對於Python來說實際上可能是相等的,然後用最接近的浮點數來近似。這是浮點數的一般屬性。

2

當浮點數工作,常見的做法是這樣的:

a == b if abs(a-b) <= eps, where eps is the required precision.

在程序設計競賽,EPS與解決問題一起被給予的。 我的建議是建立一個你需要的東西的準確性,並使用它

3

這與計算機如何存儲浮點數有關。這個的詳細描述是here。但是,對於您的情況,快速解決方案是不檢查point.x的打印表示,但是如果point.x等於4.7。所以......

>>> point = Point(4.7, 8.2) 
>>> point.x == 4.7 
True 

或者更好:

>>> point = Point(4.7, 8.2) 
>>> eps = 2**-53 #get epsilon for standard double precision number 
>>> -eps <= point.x - 4.7 <= eps 
True 

哪裏eps是在浮點運算的舍入誤差最大值。有關epsilon的詳細信息,請參見here

編輯:-eps <= point.x - 4.7 <= eps相當於abs(point.x - 4.7) <= eps。我只是補充一點,因爲不是每個人都熟悉Python的比較運算符鏈接。

編輯2:既然你提到numpy,numpy有一個方法來獲得eps,而無需自己計算它。如果您使用的是numpy,請使用eps = numpy.finfo(float).eps而不是2**-53。請注意,numpy epsilon出於某種原因比應該大,等於2**-52而不是2**-53。我不知道這是爲什麼。

+2

機器epsilon是**相對**錯誤的界限。你不能像你那樣使用它,因爲對於遠離零的值,絕對誤差會更大。在這種特殊情況下,'point.x - 4.7'總是會給出0。 – interjay 2010-08-22 17:29:00

4
>>> point.x 

電話repr功能這是字符串表示持有更多的技術信息超過str函數,該函數調用時

>>> print point.x 

發生

+1

謝謝你回答我應該問的問題 – tel 2010-08-22 18:03:01