導入:なぜ「==」を使ってはいけないのか
Javaで数値を比較する際、整数型であれば「==」演算子を迷わず使いますよね。しかし、floatやdoubleといった浮動小数点数には、実は「==」だけでは解決できない落とし穴があります。特に、計算結果が「NaN(非数)」や「正負のゼロ」になる場合、通常の比較では予期せぬバグを引き起こす可能性があります。本記事では、Javaのシニアエンジニアが現場で常識として使う、安全な比較手法を解説します。
基礎知識:浮動小数点数の厄介な特性
浮動小数点数には、通常の数値以外に特別な状態が存在します。
・NaN (Not a Number):計算不能な値(0.0 / 0.0など)。数学的には定義不能です。
・正のゼロ(0.0)と負のゼロ(-0.0):内部表現上は異なりますが、算術的には「0.0 == -0.0」は真と判定されます。
これらを「==」で比較すると、特にNaNの場合、「NaN == NaN」が偽となってしまうなど、直感に反する挙動をします。この問題を安全に解決するために用意されているのが、Float.compare() および Double.compare() です。
実装:compareメソッドの仕組み
Float.compare(f1, f2)は、以下のルールで比較を行います。
1. f1がf2より小さい場合は負の数、大きい場合は正の数を返す。
2. 等しい場合は0を返す。
3. NaNは、数値よりも大きいものとして扱われる。
4. 正のゼロは負のゼロよりも大きいものとして扱われる。
これにより、コレクションのソートや複雑な条件分岐においても、一貫性のある比較が可能になります。
サンプルプログラム
以下のコードをコピー&ペーストして、挙動を確認してみてください。
public class FloatCompareExample {
public static void main(String[] args) {
double val1 = 0.0;
double val2 = -0.0;
// 1. 通常の比較演算子での注意点
System.out.println("== による比較: " + (val1 == val2)); // trueになる
// 2. Double.compareによる比較
// 戻り値が0なら等しい、0以外なら異なることを示す
int result = Double.compare(val1, val2);
if (result == 0) {
System.out.println("Double.compare: 2つの値は等しいです");
} else {
System.out.println("Double.compare: 2つの値は異なります(結果: " + result + ")");
}
// 3. NaNの比較
double nanVal = Double.NaN;
System.out.println("NaN同士の比較(==): " + (nanVal == nanVal)); // falseになる
System.out.println("NaN同士の比較(compare): " + (Double.compare(nanVal, nanVal) == 0)); // trueになる
}
}
応用・注意点:現場で陥りやすい罠
実務で特に注意すべきは、「誤差」の扱いです。比較メソッドは「値の厳密な一致」を判定しますが、浮動小数点数の計算は誤差が生じやすいため、例えば「0.1 + 0.2 == 0.3」はfalseになります。
もし、金融計算など高い精度が必要な場合は、double型ではなく BigDecimalクラス を使用してください。compareメソッドは、あくまで「計算結果として出た値を、プログラムとして論理的に比較したいとき」に使うのがベストプラクティスです。
まとめると、浮動小数点数の比較には「==」ではなく「compareメソッド」を使う。これだけで、あなたのコードの堅牢性はぐっと向上します。ぜひ今日から取り入れてみてください。

コメント