QA@IT

Rubyで0.1を10回足して 1.0 になっていたのは間違い?

2884 PV

手元にあるいくつかのバージョンのRubyで、0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 を計算したところ、1.8系では 1.0 、1.9系では 0.9999999999999999 となりました。

~ ruby -ve 'p eval(Array.new(10, "0.1").join("+")).inspect'
rubinius 1.2.0 (1.8.7 release 2010-12-21 JI) [x86_64-apple-darwin10.6.0]
"0.9999999999999999"

~ ruby -ve 'p eval(Array.new(10, "0.1").join("+")).inspect'
ruby 1.8.6 (2010-09-02 patchlevel 420) [i686-darwin11.4.2]
"1.0"

~ ruby -ve 'p eval(Array.new(10, "0.1").join("+")).inspect'
ruby 1.8.7 (2012-02-08 patchlevel 358) [i686-darwin11.4.0]
"1.0"

~ ruby -ve 'p eval(Array.new(10, "0.1").join("+")).inspect'
ruby 1.9.3p286 (2012-10-12 revision 37165) [x86_64-darwin11.4.2]
"0.9999999999999999"

~ ruby -ve 'p eval(Array.new(10, "0.1").join("+")).inspect'
ruby 2.0.0dev (2012-10-12 trunk 37163) [x86_64-darwin11.4.2]
"0.9999999999999999"

2進法で0.1が循環小数になるため、浮動小数点の精度によって相応の誤差が出るというのが私の理解です。

では逆に、Ruby 1.8系では何が起こっていたのでしょうか? 浮動小数点演算の標準規格、IEEE 754 : Wikipedia からすると、どちらの結果が正しい、というようなことがあるのでしょうか? なぜ 1.8 と 1.9 で動作が変わったのでしょうか?

回答

内部的な計算はどちらも IEEE 754 準拠です。
1.8 が違うのは、
irb(main)> 0.99999999999999999
=> 1.0
と、1.0 にとても近い値を inspect すると 1.0 に丸めているからです。
この挙動は誤解を招くとして、1.9 では廃止されました。

編集 履歴 (0)
  • なるほど! よく分かりました。ありがとうございます。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。