問題
Rubyで0.1を足していくと、計算結果がずれるという問題が起きた。例えば、以下のようなコードを書くと、期待しているような計算結果が得られない。
> tmp = 0.0 => 0.0 > 1..10.times { p tmp += 0.1 } 0.1 0.2 0.30000000000000004 0.4 0.5 0.6 0.7 0.7999999999999999 0.8999999999999999 0.9999999999999999 => 1..10
経緯
twitterでぼやいたら、リプライで親切に教えていただけた。
https://twitter.com/kalab1998/status/421575612789035008
また、調べると浮動小数点数どうしが同値であるかを比較には「計算機イプシロン」を使って誤差を吸収しなければならないらしい。
詳しくは浮動小数点数の同値比較には計算機イプシロンを使うこと – Tociyuki::Diaryを参照。
結論
- IEEE 754の規格上の仕様
- Ruby2.1以上ならrationalリテラルを使って、
tmp = 0.0r
というように書く - Ruby2.1未満ならBigDecimalを使う
- 浮動小数点数を比較する時は計算機イプシロン Float::EPSILON を利用する
ちなみに、RT先でコンピュータサイエンスの基本を理解していないという指摘もあった。耳の痛い話だった。