這當然打破:內部舍入困境:總結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。
這當然打破:內部舍入困境:總結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。
圓形方法支持小數規範舍入到: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)
...應該是不錯的。
對不起,我忘了提及在這種情況下我被困在Ruby 1.8.7中。 – Amy 2013-03-15 09:36:38
'backports'寶石應該把它帶到那裏。 – 2013-03-15 10:43:43
準確求和和有效比較是有區別的。你說你想要前者,但看起來你希望後者。基礎的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
不要忽視提及你也可以使用Float :: EPSILON。 [重構你的near_enough?](https://gist.github.com/kotp/5173308)方法就像這樣。 – vgoff 2013-03-15 21:43:29
@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
我不知道這是不是你的博客,但如前所述,很多事情要考慮,並且絕對不會低於1.0。如果我必須比較浮點數,我通常會嘗試確定精度級別,並比較一些誤差範圍之間的差異。仍然沒有找到我最喜歡的方式來做到這一點。感謝您的博客文章鏈接。 – vgoff 2013-03-16 07:45:51
浮點comparations通常經由完成'如果ABS(V1-V2)
Vesper
2013-03-15 09:28:24
其實。這可能是我聽到的更好的簡短答案:((0.1 + 0.1 + 0.1) - 0.3).abs <0.0001 – Amy 2013-03-15 09:41:13