Code Fix

中級

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.3Math.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パターンを実際に手で直すと、エラーメッセージのどこを読めばよいかが掴めます。

演習をはじめる

関連するエラー

広告
広告スロット(未設定)