はじめに
前々から「0.1+0.2=0.3000.....0004
と0.3にならないのは何でだろう??」といった疑問を持っていましたものの、当時は深掘りをしていませんでした。下記が問題のソースコードです。
console.log(0.1+0.2); // 0.30000000000000004
最近、Javascriptで勉強を始める中で、その理由について解説しており腑に落ちたので、本記事にて共有します。
0.1 + 0.2 ≠ 0.3となる理由
実は0.1や0.2は...
実は0.1や0.2もコンピュータの世界では、「0.1」や「0.2」と表現されないのです。
その理由として、コンピュータ上では2進数で表記されることより、0.1や0.2を正確に表すことができなくなっています。実際に計算される2進数表記(toString(進数)
)、正確な数値(toFixed(桁数)
)をそれぞれ表現をすると、下記のようになります。
/* 0.1 */
// 2進数表記:0.0001100110011001100110011001100110011001100110011001101
console.log((0.1).toString(2));
// 正確な数値:0.1000000000000000055511151231257827021181583404541015625
console.log((0.1).toFixed(100));
/* 0.2 */
// 2進数表記:0.001100110011001100110011001100110011001100110011001101
console.log((0.2).toString(2));
// 正確な数値:0.200000000000000011102230246251565404236316680908203125
console.log((0.2).toFixed(100));
注) 上記の記述の場合、正確な数値にて本来は100桁分表示するので0が続くのですが、今回は説明の都合上割愛しています。
ソースコードより、2進数表記はいずれも00110011...
と循環しており、最後の桁で...1101
と切り上げていることが確認できます。この切り上げの影響により、0.1や0.2を正確に割り出すと微小な丸め誤差が発生するのです。
0.1 + 0.2 ≠ 0.3となる正体は何なのか?
こちらについても、上記で説明したような 「切り上げ」 の影響を受けた結果として、0.1 + 0.2 ≠ 0.3
となります。実際に、0.1+0.2
と0.3
について2進数表記で比較すると下記のようになります(分かりやすいように、出力結果の項目で比較します)。
// 入力
console.log((0.1+0.2).toString(2));
console.log((0.3).toString(2));
// 出力結果
// 0.010011001100110011001100110011001100110011001100110100 (0.1+0.2)
// 0.010011001100110011001100110011001100110011001100110011 (0.3)
上記のように、2進数で比較した場合に誤差が発生することについて確認できます。
この切り上げられた数値同士が加算されることによって、最初に掲げた問題となる下記のような出力結果が生まれます。
console.log(0.1+0.2); // 0.30000000000000004
最後に
0.1 + 0.2 ≠ 0.3
になる理由として、
- 2進数表記で表すと切り上げが発生すること
- 切り上げた数値同士を加算することで、目に見える誤差が発生すること
がありました。
皆さんのお役に立てれば幸いです!