JavaScript再入門~浮動小数点~


CodeIQで「はしれ!モード学園」という漫画が公開され、話題になってたので問題をやってみましたが、つまずいたのが浮動少数点の問題。
なので自分のためにも問題の解説をまとめておきます。
漫画:https://codeiq.jp/magazine/2015/10/30057/
問題:https://codeiq.jp/q/2378

問題

次のコードを実行した時に出力されるのは?

var i = 0;
var cnt = 0;
while (i < 1) {
    cnt ++;
    i += 0.1;
}
console.debug(cnt);

解答

私は深く考えず、すぐに「10」だと思ってしまいましたが、
答えは「11」でした。

考察

問題のコードでwhile文の中でiを出力するコードを追加して検証しました。
すると以下のようになります。

0.3のところもおかしいですが、、、
0.7のあとから誤差で少しずつずれが生じています。

丸め誤差

原因は丸め誤差というものです。
10進数0.1を2進数に変換すると、10進数では有限けたであるのに、2進数では無限小数(循環少数)となってしまいます。いま、小数点以下5桁までしか表現できないとすると、下記の式の編みかけ部分は表現できず、これにより、丸め誤差が発生します。
0.1 = 0.000110011……(2進数)
編みかけ部分が表現できず丸められた値$=2^{-4}+2^{-5}=0.009375$
絶対誤差=|0.09375-0.1|=0.00625
これだけの誤差が生じます。
※これは例えなので、JavaScriptでこの誤差が生じているわけではありません