【Java学習|初心者向け】Javaで浮動小数点の計算が合わない?誤差の正体と正しい対処法

1. 導入:なぜ0.1 + 0.2は0.3にならないのか?

Javaの学習を始めたばかりの方が、算術演算子を使って計算をしていて「計算結果が微妙にズレている」という現象に遭遇したことはありませんか?実は、0.1 + 0.2を計算すると、期待される0.3ではなく「0.30000000000000004」といった値が返ってきます。これはバグではなく、コンピュータが数字を扱う仕組みに起因する「浮動小数点の精度誤差」です。金融システムや正確な数値計算が求められる現場では、この誤差を正しく理解し回避することが不可欠です。

2. 基礎知識:コンピュータはなぜ小数で間違うのか

Javaの基本型である「double」や「float」は、IEEE 754という規格に基づいています。コンピュータは内部で数字を2進数で扱っていますが、0.1のような「10進数で割り切れる小数」を2進数に変換すると「0.0001100110011…」のように無限小数になってしまいます。有限のメモリ(64ビットなど)で表現するために、どこかで切り捨て(丸め)が発生し、それが積み重なって誤差となります。そのため、if文で「if (a == 0.3)」のように直接比較するのは非常に危険です。

3. 実装/解決策:BigDecimalクラスを使おう

正確な計算が必要な場合、Javaでは「java.math.BigDecimal」クラスを使用するのが鉄則です。このクラスを使うと、10進数を文字列として扱うことで誤差を完全に排除できます。

4. サンプルプログラム

以下のコードをコピーして、実際に動作を確認してみてください。

import java.math.BigDecimal;

public class PrecisionExample {
    public static void main(String[] args) {
        // 1. double型の危険な計算例
        double d1 = 0.1;
        double d2 = 0.2;
        double result = d1 + d2;
        System.out.println("doubleの計算結果: " + result); // 0.30000000000000004 となる

        // 2. BigDecimalを使った正しい計算例
        // 必ず「文字列」として数値を渡してください(doubleで渡すと誤差が引き継がれます)
        BigDecimal b1 = new BigDecimal("0.1");
        BigDecimal b2 = new BigDecimal("0.2");
        BigDecimal bResult = b1.add(b2);
        
        System.out.println("BigDecimalの計算結果: " + bResult.toString()); // 正確に 0.3 となる
        
        // 3. 比較の際も equals や compareTo を使う
        if (bResult.compareTo(new BigDecimal("0.3")) == 0) {
            System.out.println("比較結果: 正しく0.3と判定されました!");
        }
    }
}

5. 応用・注意点:現場での鉄則

最後に、現場で役立つ注意点を3つお伝えします。

コンストラクタには文字列を渡す: 「new BigDecimal(0.1)」と書くと、浮動小数点の誤差をそのままオブジェクト化してしまいます。必ず「new BigDecimal(“0.1”)」と文字列で渡しましょう。
比較には compareTo を使う: BigDecimal同士の比較には「==」ではなく「compareTo」メソッドを使用します。戻り値が0であれば「等しい」と判断します。
厳密な数値以外は使い分ける: 物理シミュレーションなど、速度が優先され誤差を許容できる場合はdoubleを使っても問題ありません。しかし、金額計算や税率計算には必ずBigDecimalを使うというルールを徹底してください。

最初は少し手間に感じるかもしれませんが、この「正確さへのこだわり」が、将来的にバグの少ない堅牢なシステムを作る第一歩になります。ぜひプロジェクトで活用してください。

コメント

タイトルとURLをコピーしました