1. ホーム
  2. language-agnostic

[解決済み] 浮動小数点数の比較はどのようにすればよいのですか?

2022-12-10 05:16:58

質問

私は現在、以下のようなコードを書いています。

double a = SomeCalculation1();
double b = SomeCalculation2();

if (a < b)
    DoSomething2();
else if (a > b)
    DoSomething3();

そして、他の場所では、等式を行う必要があるかもしれません。

double a = SomeCalculation3();
double b = SomeCalculation4();

if (a == 0.0)
   DoSomethingUseful(1 / a);
if (b == 0.0)
   return 0; // or something else here

要するに、浮動小数点演算がたくさん行われていて、条件のためにいろいろな比較をする必要があるのです。この文脈ではそんなことは無意味なので、整数演算に変換することはできない。

こんなことがあり得るので、浮動小数点数の比較は信頼性に欠けると以前読んだことがあります。

double a = 1.0 / 3.0;
double b = a + a + a;
if ((3 * a) != b)
    Console.WriteLine("Oh no!");

要するに、私は知りたいのです。浮動小数点数の比較 (より小さい、より大きい、等しい) を確実に行うにはどうしたらよいでしょうか。

私が使用している数値範囲は、およそ10E-14から10E6までなので、大きな数値だけでなく小さな数値も扱う必要があります。

私はどの言語を使用しているかに関係なく、これを達成する方法に興味があるので、私はこれを言語に依存しないとしてタグ付けしました。

どのように解決するのですか?

大小の比較は、float/倍精度の限界ぎりぎりで作業していない限り、実際には問題にはなりません。

fuzzy equals" の比較のために、次のようなものを思いつきました (Java コードです。簡単に適用できるはずです)。 浮動小数点数ガイド のために、多くの作業と多くの批判を考慮した結果です。

public static boolean nearlyEqual(float a, float b, float epsilon) {
    final float absA = Math.abs(a);
    final float absB = Math.abs(b);
    final float diff = Math.abs(a - b);

    if (a == b) { // shortcut, handles infinities
        return true;
    } else if (a == 0 || b == 0 || diff < Float.MIN_NORMAL) {
        // a or b is zero or both are extremely close to it
        // relative error is less meaningful here
        return diff < (epsilon * Float.MIN_NORMAL);
    } else { // use relative error
        return diff / (absA + absB) < epsilon;
    }
}

テストスイートが付属しています。なぜなら、1つの値0、0と反対の2つの非常に小さな値、または無限大のようないくつかのエッジケースで失敗することが事実上保証されているからです。

代替案 (詳細については上記のリンクを参照) は、浮動小数点数のビット パターンを整数に変換し、一定の整数の距離内のすべてを受け入れることです。

いずれにせよ、すべてのアプリケーションに完璧に対応するソリューションはおそらく存在しません。理想的には、実際の使用事例をカバーするテスト スイートで独自のものを開発/適応させることです。