0.1 + 0.2 が 0.3 にならない理由
2進小数の限界です。誤差を許容する比較と、金額計算でBigDecimalを使う理由を扱います。
なぜエラーが出ないのか
出力: false
(エラーなし)- javacは何も報告しません。文法として正しいためです
出力: false- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 public class Main { 2 public static void main(String[] args) { 3 double a = 0.1 + 0.2; 4 System.out.println(a == 0.3 ); ^ 5 } 6 }
出力: false期待: true (コンパイルは通っています)
2進小数では0.1が正確に表せません。浮動小数点の比較は誤差を許容する形で書きます。
直し方: a == 0.3 を Math.abs(a - 0.3) < 1e-9 にします。
広告
広告スロット(未設定)
パターン2
1 public class Main { 2 public static void main(String[] args) { 3 System.out.println(0.1 + 0.2 == 0.3); ^ 4 } 5 }
出力: 5.551115123125783E-17(誤差そのものが見えます)
差を取ると誤差の実体が見えます。金額計算にはBigDecimalを使うのが正解です。
直し方: == を - にします。
パターン3
1 import java.math.BigDecimal; 2 3 public class Main { 4 public static void main(String[] args) { 5 BigDecimal a = new BigDecimal(0.1 ); ^ 6 System.out.println(a); 7 } 8 }
出力: 0.1000000000000000055511151231257827021181583404541015625期待: 0.1 (コンパイルは通っています)
doubleを渡すと誤差ごと取り込まれます。BigDecimalには文字列で渡すのが鉄則です。
直し方: 0.1 を "0.1" にします。
よくある誤解
floatをdoubleに変えても解決しません。精度が上がるだけで、2進小数で表せない値がある事実は変わりません。
まとめ
0.1 + 0.2 が 0.3 にならない理由は中級でつまずきやすい項目です。上の3パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。