2017-08-08 111 views
2

標題有點誤導,因爲它不完全是x和x,它是x和0.3;然而,值應該是相同的。爲什麼x <= x false?

我:

arr = np.arange(0, 1.1, 0.1) 

,我得到:

arr[arr <= 0.3] 
> array([0., 0.1, 0.2]) 

正確的結果應該是:

arr[arr <= 0.3] 
> array([0., 0.1, 0.2, 0.3]) 

我還沒有偶然發現了這個問題。我知道它與浮點精度有關......但我能在這裏做什麼?

+0

嗯......'改編[編曲。 round(1)<= 0.3]'... –

+0

所以我應該在執行任何比較之前總是*整數? – Xiphias

+1

花車之間的等價性總是有風險的事情來測試。 –

回答

4

不要依靠比較花車的平等(除非你知道正好你正在處理的花車)。 既然你知道用來生成陣列是0.1步長,

arr = np.arange(0, 1.1, 0.1) 

,你可以提高閾值,0.3的,由半數步長找到了新的閾值,且在arr值之間的安全:

In [48]: stepsize = 0.1; arr[arr < 0.3+(stepsize/2)] 
Out[48]: array([ 0. , 0.1, 0.2, 0.3]) 

順便說一句,在np.arange(0, 1.1, 0.1)1.1是同樣的想法的一個應用 - 定的浮點運算的變幻莫測,我們也不能肯定這1.0將是如果我們寫了np.arange(0, 1.0, 0.1),那麼這個結果就會增加,所以右邊的終點增加了stepize。


從根本上說,這個問題歸結爲floating-point arithmetic being inaccurate

In [17]: 0.1+0.2 == 0.3 
Out[17]: False 

所以在陣列中的第四值大於0.3一點點。

In [40]: arr = np.arange(0,1.1, 0.1) 
In [41]: arr[3] 
Out[41]: 0.30000000000000004 

注意,舍入可能不是一個可行的解決方案。例如, 如果arr具有D型細胞float128

In [53]: arr = np.arange(0, 1.1, 0.1, dtype='float128') 

In [56]: arr[arr.round(1) <= 0.3] 
Out[56]: array([ 0.0, 0.1, 0.2], dtype=float128) 

雖然使float128製成arr[3]接近小數0.3 D型,

In [54]: arr[3] 
Out[54]: 0.30000000000000001665 

現在四捨五入不會產生數小於0.3:

In [55]: arr.round(1)[3] 
Out[55]: 0.30000000000000000001 
+1

即使你不知道步長,你*仍然可以做類似'arr [arr <= 0.3 + sys.float_info.epsilon] - 但是,我並不完全相信它會*總是*足以保證比較工作...你有什麼想法? –

+0

雖然 - 上面似乎也適用於你的'float128'範例... –

+0

我不確定如何量化'np.arange(...)'中的值可能離他們多遠理想化的小數對應。根據浮點數,連續浮點數之間的差距會發生變化,並且可能會大於'sys.float_info.epsilon'。例如, 'x = 10.3; (np.nextafter(x,np.inf) - x)> sys.float_info.epsilon'。 – unutbu

1

Unutbu指出了主要問題。您應該避免比較浮點數,因爲它們有四捨五入的錯誤。

然而,這是一個很多人遇到的問題,因此有一個函數可以幫助你解決這個問題; np.isclose你的情況,這將導致:

arr[np.logical_or(arr <= 0.3, np.isclose(0.3, arr))] 
>>> array([0., 0.1, 0.2, 0.3]) 

在這種情況下,這可能不是最好的選擇,但它可能有助於瞭解該功能。

旁註: 如果沒有人向你解釋過,爲什麼會發生這種情況。基本上,計算機將所有內容保存爲二進制文件,但0.1是二進制的週期數,這意味着計算機無法保存所有數字(因爲數量無限多)。十進制等效是:

1/3 + 1/3 + 1/3 = 0.33333 0.33333 + 0.33333 + = 0.99999

這是不是1

相關問題