2012-01-12 34 views
2

首先,我不是一個數學家,所以大量的精度很少過濾到我的日常工作中。請溫柔。 )Python 32/64位機器浮點移位矩陣求和不正確?

使用NumPy的,以產生具有從值1相等地劃分的矩陣:

>>> m = numpy.matrix([(1.0/1000) for x in xrange(1000)]).T 
>>> m 
matrix[[ 0.001 ], 
     [ 0.001 ], 
     ... 
     [ 0.001 ]]) 

在64位的Windows與Python 2.6,求和很少工程以1.0。 math.fsum()對這個矩陣有影響,但如果我改變矩陣使用更小的數字,則不會。

>>> numpy.sum(m) 
1.0000000000000007 
>>> math.fsum(m) 
1.0 
>>> sum(m) 
matrix([[ 1.]]) 
>>> float(sum(m)) 
1.0000000000000007 

在帶有Python 2.6的32位Linux(Ubuntu)上,求和總是可以達到1.0。

>>> numpy.sum(m) 
1.0 
>>> math.fsum(m) 
1.0 
>>> sum(m) 
matrix([[ 1.]]) 
>>> float(sum(m)) 
1.0000000000000007 

我可以評估時的埃普西隆添加到我的代碼,如果矩陣款項1(例如-epsilon <總和(M)< +小量),但我想先了解一下該差異的原因是內Python,以及是否有更好的方法來正確確定總和。

我的理解是,總和正在處理數字(浮點數)的機器表示方式與它們的顯示方式不同,並且在求和時使用內部表達式。但是,看看我用來計算總和的3種方法,不清楚它們爲什麼不同,或者平臺之間是相同的。

什麼是正確計算矩陣總和的最佳方法?

如果你正在尋找一個更有趣的矩陣,這個簡單的變化將有較小的矩陣編號:

>>> m = numpy.matrix([(1.0/999) for x in xrange(999)]).T 

在此先感謝您的幫助!

更新 我想我想出了一些東西。如果我將存儲的值更正爲32位浮點值,則結果與32位Linux求和值相匹配。

>>> m = numpy.matrix([(numpy.float32(1.0)/1000) for x in xrange(1000)]).T 
>>> m 
matrix[[ 0.001 ], 
     [ 0.001 ], 
     ... 
     [ 0.001 ]]) 
>>> numpy.sum(m) 
1.0 

這將設置矩陣機數來表示在我的Windows測試32位浮點,不64位,並且將正確總結。爲什麼0.001浮點數不等於32位和64位系統上的機器編號?如果我試圖存儲具有許多小數位的非常小的數字,我希望它們會有所不同。

有沒有人對此有任何想法?在這種情況下,我應該明確地切換到32位浮點數,還是有64位求和方法?或者我回到添加一個epsilon?對不起,如果我聽起來很愚蠢,我對意見很感興趣。謝謝!

+4

您*必須*使用ε,因爲你必須永遠* *比較浮點數的確切平等。 *特別*你知道的數字是算術的結果,而不是例如。常量或配置值,例如。 – unwind 2012-01-12 16:55:52

+0

@unwind:永遠不要說永遠。精確的相等測試有時在浮點上是合適和必要的。但是,這不是其中之一。 – 2012-01-12 16:57:46

+0

您可能想了解[浮點數](http://en.wikipedia.org/wiki/Floating_point)是如何工作的。知道什麼時候做什麼是很有用的。 – murgatroid99 2012-01-12 17:03:22

回答

2

這是因爲你比較32位浮點64位浮點,因爲你已經發現了。

如果指定在兩臺機器上32位或64位D型,你會看到同樣的結果。

numpy的默認浮點D型細胞(數值類型爲numpy的陣列)是一樣的機器精度。這就是爲什麼你在不同的機器上看到不同的結果。

E.g. 的32位版本:

m = numpy.ones(1000, dtype=numpy.float32)/1000 
print repr(m.sum()) 

和64位版本:

m = numpy.ones(1000, dtype=numpy.float64)/1000 
print repr(m.sum()) 

會有所不同,由於不同的精度,但你會看到在不同的機器相同的結果。 (然而,64位的操作會比較慢在32位機器上)

如果你只是指定numpy.float,這將是要麼依賴於計算機的本地架構的float32float64

2

我會說,最準確的方法(不是最有效的)是使用decimal module

>>> from decimal import Decimal 
>>> m = numpy.matrix([(Decimal(1)/1000) for x in xrange(1000)]) 
>>> numpy.sum(m) 
Decimal('1.000') 
>>> numpy.sum(m) == 1.0 
True 
+0

這也可以做到。這個人只是讓我想改變我的問題。十進制應該精確地表示數值。但是在32位和64位浮點數之間,爲什麼0.001浮點數不能等同地表示爲機器號? – garlicman 2012-01-12 17:14:34

+0

哦,我同意,十進制不是很有效。在使用小數之前,我會切換到epsilon,但是謝謝您的建議! – garlicman 2012-01-12 17:18:46

+1

有關python中浮點運算的更多信息,您可能需要查看[here](http://docs.python.org/tutorial/floatingpoint.html)。 – jcollado 2012-01-12 17:30:37

2

首先,如果您使用numpy的存儲值,你應該使用numpy的的方法,如果提供,以處理陣列/矩陣。也就是說,如果你想要相信那些把numpy放在一起的非常有能力的人。

現在,numpy的sum()的64位答案無法精確到1,因爲計算機中處理浮點數的原因(murgatroid99爲您提供了一個鏈接,還有數百個鏈接) 。 因此,唯一安全的方法,(甚至對理解你的代碼的數學處理更好,因此你的問題本身也非常有幫助)就是使用一個epsilon值以一定的精度截斷。

爲什麼我認爲這是有幫助嗎?因爲計算科學需要像實驗科學一樣處理錯誤,並且通過故意在這個地方處理(意思是確定它們)錯誤,您已經完成了處理代碼計算錯誤的第一步。

因此,有可能其他的方法來處理它,但大多數的時候,我會用的ε來確定我需要一個給定的問題的精度。