2013-03-15 43 views
3

這當然打破:內部舍入困境:總結Ruby浮點數的準確方法?

(0.1 + 0.1 + 0.1) => 0.30000000000000004 

(0.1 + 0.1 + 0.1) == 0.3 # false 

我並不需要一個完美的總和,只是不夠好,說兩輛花車相同的值。我能想出的最好的結果是將等式兩邊相乘。這是最好的方法嗎?

((0.1 + 0.1 + 0.1) * 1000).round == (0.3 * 1000).round 

更新:我被困在Ruby v1.8.7。

+7

浮點comparations通常經由完成'如果ABS(V1-V2) Vesper 2013-03-15 09:28:24

+0

其實。這可能是我聽到的更好的簡短答案:((0.1 + 0.1 + 0.1) - 0.3).abs <0.0001 – Amy 2013-03-15 09:41:13

回答

0

圓形方法支持小數規範舍入到:http://www.ruby-doc.org/core-1.9.3/Float.html#method-i-round

所以

(0.1 + 0.1 + 0.1).round(1) == (0.3).round(1) 

...應該是不錯的。

+0

對不起,我忘了提及在這種情況下我被困在Ruby 1.8.7中。 – Amy 2013-03-15 09:36:38

+0

'backports'寶石應該把它帶到那裏。 – 2013-03-15 10:43:43

1

準確求和和有效比較是有區別的。你說你想要前者,但看起來你希望後者。基礎的Ruby浮點運算是IEEE,並且具有用於最小化累積誤差的合理語義,但是總是會在使用不能精確表示所有值的表示時發生。爲了精確模擬誤差,FP加法不應該產生精確的值,它應該產生一個間隔,並且進一步的加法將按間隔操作。

實際上,許多應用程序不需要詳細計算錯誤,他們只需要進行計算並知道比較不準確,輸出的十進制表示應該舍入。

下面是Float的一個簡單擴展,它可以幫助您比較。它或類似的東西應該在stdlib中,但不是。

class Float 
    def near_enough?(other, epsilon = 1e-6) 
    (self - other.to_f).abs < epsilon.to_f 
    end 
end 

pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3) 
=> true 
pry(main)> (0.1 + 0.1 + 0.1).near_enough?(0.3, 1e-17) 
=> false 
pry(main)> ([0.1] * (10**6)).reduce(:+).near_enough?(10**5, 1e-5) 
=> true 
pry(main)> ([0.1] * (10**6)).reduce(:+).near_enough?(10**5) 
=> false 

採摘適當epsilon可以是在一般情況下棘手。您應該閱讀What Every Computer Scientist Should Know About Floating-Point Arithmetic。我發現布魯斯道森的浮點技巧博客很好,這裏是他的章節Comparing Floating Point Numbers

如果你真的關心準確性,你可以用一個確切的表示法來做你的算術。 Ruby提供了一個Rational類(甚至回到1.8),讓你對分數進行精確的算術運算。

pry(main)> r=Rational(1,10) 
=> (1/10) 
pry(main)> (r + r + r) == Rational(3,10) 
=> true 
pry(main)> (r + r + r) == 0.3 
=> true 
pry(main)> r.to_f 
=> 0.1 
pry(main)> (r + r + r).to_f 
=> 0.3 
+0

不要忽視提及你也可以使用Float :: EPSILON。 [重構你的near_enough?](https://gist.github.com/kotp/5173308)方法就像這樣。 – vgoff 2013-03-15 21:43:29

+0

@vgoff Float :: EPSILON不是一個很好的通用epsilon。 [對於1.0和2.0之間的數字FLT_EPSILON表示相鄰浮點數之間的差異。對於小於1.0的數字,FLT_EPSILON的一個小數值很快就會變得太大,並且數目足夠小,FLT_EPSILON可能會大於您正在比較的數字](http://www.altdevblogaday.com/2012/02/22/comparing-floating - 點數 - 2012年版/) – dbenhur 2013-03-15 22:18:37

+0

我不知道這是不是你的博客,但如前所述,很多事情要考慮,並且絕對不會低於1.0。如果我必須比較浮點數,我通常會嘗試確定精度級別,並比較一些誤差範圍之間的差異。仍然沒有找到我最喜歡的方式來做到這一點。感謝您的博客文章鏈接。 – vgoff 2013-03-16 07:45:51