0.1 + 0.2 の内部で何が起きるか詳しく教えて
この「0.1 + 0.2 がなぜ 0.3 にならないのか」は、JavaScript の数値の正体(IEEE 754) を理解するうえで、非常に大事なテーマです。
では、初心者にもわかるように コンピュータの中で何が起きているか をステップごとに見ていきましょう。
1. JavaScript の数値は全部「倍精度浮動小数点数(IEEE 754形式)」
JavaScript では 整数も小数も区別せずに「number型」 として扱います。
内部的には、すべてが IEEE 754 Double Precision(64ビット浮動小数点数) という形式で保存されています。
64ビットの内訳
| 区間 | 意味 | ビット数 |
|---|---|---|
| 符号部 | 正か負か | 1 |
| 指数部 | 桁(2の何乗か) | 11 |
| 仮数部(小数部) | 実際の値の細かい部分 | 52 |
この「仮数部」の52ビットが、0と1でしか表せないために誤差が発生します。
2. 0.1 は2進数では「割り切れない」
10進数の 0.1 を 2進数にすると、こうなります。
0.1(10) = 0.0001100110011001100110011001100...(2)
JavaScriptそう、永遠に続く循環小数なんです。
でも、コンピュータは有限のビット数しか扱えないので、
途中で 切り捨て てしまいます(52ビット分しか保存できない)。
3. 実際に保存される「0.1」の近似値
保存されている実際の値(近似)は:
0.1000000000000000055511151231257827021181583404541015625
JavaScriptつまり、ほんの少し大きいんです。
4. 同じく「0.2」も完全には表せない
0.2(10) = 0.0011001100110011...(2)
JavaScriptこちらも無限に続くので切り捨て。
保存される近似値は:
0.200000000000000011102230246251565404236316680908203125
JavaScriptつまり、これも少し大きい。
5. 足し算すると…
ではこの2つを足してみましょう。
(0.10000000000000000555…) +
(0.20000000000000001110…) =
0.30000000000000001665…
JavaScriptこれを64ビットの範囲に丸めて保存すると:
0.30000000000000004
JavaScriptとなります。
6. 「0.3」は別の近似値
ちなみに「0.3」そのものも、内部では次のような近似値になります:
0.299999999999999988897769753748434595763683319091796875
JavaScriptつまり、「0.1 + 0.2」と「0.3」は厳密に異なるビット列を持っているのです。
7. 実際に確認してみよう
console.log(0.1 + 0.2 === 0.3); // false
console.log(0.1 + 0.2); // 0.30000000000000004
JavaScript0.1 + 0.2の結果は「0.30000000000000004」0.3の内部表現は「0.2999999999999999889…」
だから、ほんのわずかに違うので false になるわけです。
8. この誤差にどう対処するか?
実務では、こういった誤差を防ぐために次のような方法がよく使われます。
✅ 方法1:toFixed() や Math.round() で丸める
let result = 0.1 + 0.2;
result = Math.round(result * 100) / 100;
console.log(result); // 0.3
JavaScript→ 小数第2位で丸めることで、見た目・計算上も「0.3」として扱える。
✅ 方法2:整数として計算する(通貨計算の定番)
let result = (10 + 20) / 100; // 10円 + 20円 のように「整数」で扱う
console.log(result); // 0.3
JavaScript→ 金額計算では、円やセントなど最小単位(整数)で処理し、最後に小数点を付けるのが安全。
✅ 方法3:専用の精密計算ライブラリを使う
たとえば:
これらは 誤差なしで小数計算を行う ライブラリです。
まとめ
| 現象 | 原因 | 対処法 |
|---|---|---|
0.1 + 0.2 ≠ 0.3 | 2進数で0.1, 0.2を正確に表せない | 丸め処理 or 整数計算 |
| 浮動小数点誤差 | IEEE754の仕様(52bit制限) | BigInt / decimal.js |
==ではOKでも===でNG | 型や誤差が違う | 数値誤差を丸めて比較 |

