浮動小数点値を比較するのはどれくらい危険ですか? 質問する

浮動小数点値を比較するのはどれくらい危険ですか? 質問する

解像度に依存しない座標系なので、よくUIKit使われます。CGFloat

しかし、例えば気分が悪くなるframe.origin.xかどうか毎回確認したいのです。0

if (theView.frame.origin.x == 0) {
    // do important operation
}

、、、、とCGFloat比較すると誤検出が発生しやすくなりません。これは浮動小数点であり、次のような不正確さの問題があります。==<=>=<>0.0000000000041

比較時にこれを内部的に処理していますか、それともゼロとして読み取られる a が true と比較されないObjective-Cことが起こる可能性がありますか?origin.x0

ベストアンサー1

まず第一に、浮動小数点値の動作は「ランダム」ではありません。実際の使用では、正確な比較は意味があり、実際に意味があります。しかし、浮動小数点を使用する場合は、その動作を知っておく必要があります。浮動小数点が実数のように動作すると想定すると、すぐに壊れるコードが作成されます。浮動小数点の結果には大きなランダムなファズが関連付けられていると想定すると (ここでの回答のほとんどが示唆しているように)、最初は機能しているように見えても、最終的には大きなエラーと壊れたコーナーケースが発生するコードが作成されます。

まず、浮動小数点を使ってプログラミングしたい場合は、これを読んでください。

浮動小数点演算についてコンピュータ科学者が知っておくべきこと

はい、全部読んでください。それが負担が大きすぎる場合は、読む時間ができるまで、計算には整数/固定小数点を使用してください。 :-)

さて、そうは言っても、正確な浮動小数点比較に関する最大の問題は次のようになります。

  1. scanfソースに書き込んだり、またはstrtodで読み込んだりする多くの値は浮動小数点値として存在せず、最も近い近似値に暗黙的に変換されるという事実。これは、demon9733 の回答で言及されていたことです。

  2. 実際の結果を表すのに十分な精度がないため、多くの結果が丸められるという事実。これを確認する簡単な例として、x = 0x1fffffeと をy = 1浮動小数点数として加算します。ここで、 はx仮数部に 24 ビットの精度 (OK) を持ち、 はy1 ビットしかありませんが、これらを加算すると、それらのビットは重複する場所になく、結果には 25 ビットの精度が必要になります。代わりに、丸められます (0x2000000デフォルトの丸めモードでは に)。

  3. 正しい値を得るには無限の桁数が必要なため、多くの結果が丸められるという事実。これには、1/3 のような有理数の結果 (10 進数では無限の桁数が必要になるのでよく知られています) だけでなく、1/10 (5 は 2 の累乗ではないため、2 進数でも無限の桁数が必要になります) や、完全な平方数ではないものの平方根のような無理数の結果も含まれます。

  4. 二重丸め。一部のシステム (特に x86) では、浮動小数点式は、その公称型よりも高い精度で評価されます。つまり、上記のいずれかの丸めが発生すると、最初に結果を高精度の型に丸め、次に最終的な型に丸めるという 2 つの丸め手順が実行されます。例として、1.49 を整数 (1) に丸めた場合と、最初に小数点 1 桁に丸め (1.5)、次にその結果を整数 (2) に丸めた場合を比較してみましょう。これは、実際には浮動小数点を扱う上で最も厄介な領域の 1 つです。コンパイラ (特にバグの多い非準拠コンパイラ (GCC など)) の動作は予測不可能だからです。

  5. 超越関数 ( trig、、など) はexplog結果が正しく丸められるとは指定されていません。結果は、精度の最後の桁 (通常1ulpと呼ばれます) の 1 単位以内で正確であると指定されるだけです。

浮動小数点コードを書くときは、数値をどのように扱うかによって結果が不正確になる可能性があることを念頭に置き、それに応じて比較を行う必要があります。多くの場合、「イプシロン」で比較するのが理にかなっています。ただし、そのイプシロンは絶対定数ではなく、比較する数値の大きさに基づいて決める必要があります。(絶対定数イプシロンが機能する場合、それは浮動小数点ではなく固定小数点が適切なツールであることを強く示唆しています。)

編集:特に、大きさ相対イプシロン チェックは次のようになります。

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y))

FLT_EPSILON定数はどこから来ますかfloat.h(これをs またはDBL_EPSILONsに置き換えます)、 は、計算の累積誤差が最後の場所で単位によって確実に制限されるように選択した定数です(誤差制限の計算が正しいかどうかわからない場合は、計算で示された値よりも数倍大きくしてください)。doubleLDBL_EPSILONlong doubleKKK

最後に、これを使用する場合、非正規化数では意味をなさないため、ゼロ付近では特別な注意が必要になる可能性があることに注意してくださいFLT_EPSILON。簡単な修正方法は、次のようにすることです。

if (fabs(x-y) < K * FLT_EPSILON * fabs(x+y) || fabs(x-y) < FLT_MIN)

同様に、DBL_MINdouble を使用する場合も置き換えます。

おすすめ記事