18

2つの浮動小数点数があり、それらを比較したいとします。一方が他方よりも大きい場合、プログラムは1つのフォークを取る必要があります。反対のことが当てはまる場合は、別のパスを取る必要があります。そして、比較されている値が、それでも真と比較されるはずの方向にごくわずかに微調整されている場合は、同じことを行う必要があります。

言い表すのは難しい質問なので、それを実証するためにこれを書きました-

float a = random();
float b = random();  // always returns a number (no infinity or NaNs)

if(a < b){
    if( !(a < b + FLOAT_EPISILON) ) launchTheMissiles();
    buildHospitals();

}else if(a >= b){
    if( !(a >= b - FLOAT_EPISILON) ) launchTheMissiles();
    buildOrphanages();

}else{
    launchTheMissiles();  // This should never be called, in any branch
}

このコードを考えると、launchTheMissiles()決して呼び出されないことが保証されていますか?

4

5 に答える 5

13

それを保証でき、NaNまたは無限大abはない場合は、次のことを実行できます。

if (a<b) {
    …
} else {
    …
}

無限大とNaNを除くすべての浮動小数点値のセットは、全順序付けを構成します(ゼロの表現が2つあるグリッチがありますが、それは問題ではありません)。これは、通常の整数のセットでの作業と同じです。唯一の違いは整数の場合のように、後続の値の間の間隔の大きさが一定ではないということです。

実際、IEEE 754は、同じ符号の非NaN非無限大値の比較が、通常の整数と同じ操作で実行できるように設計されています(ここでも、ゼロのグリッチがあります)。したがって、この特定のケースでは、これらの数値を「より良い整数」と考えることができます。

于 2013-03-12T23:56:26.347 に答える
4

簡単に言えば、決して呼び出されないことが保証されています。

その場合a<b、aは常にb +正の量より小さくなりますが、小さいです。その場合、aがb+量よりも小さいかどうかのテストは真になります。

3番目のケースには到達しません。

于 2013-03-12T23:50:37.733 に答える
2

IEEE 754(浮動小数点)標準では、加算または減算によって正または負の無限大が生じる可能性があるため、bがFLT_MAXまたは-FLT_MAXの場合、b+FLOAT_EPSILONおよびb--FLOAT_EPSILONは正または負の無限大になる可能性があります。浮動小数点標準では、FLT_MAX <+ infinityがtrueを返し、-FLT_MAX> -infinityを返すことで、無限大が期待どおりに比較されることも規定されています。

浮動小数点の形式と精度の問題を実用的な観点から詳しく調べるには、ChristerEricsonの著書RealTimeCollisionDetectionまたはBruceDawsonのブログ投稿を参照することをお勧めします。 !)はhttp://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/にあります。

于 2013-03-13T00:08:37.817 に答える
2

不平等のテストは、平等のテストと同様に正確です。人々は、自分たちが取り組んでいる価値観が自分たちが思っているものと正確に一致していない可能性があることに気付いていないため、混乱します。したがって、はい、最後の関数呼び出しに関するコメントは正しいです。そのブランチは決して取られません。

于 2013-03-13T01:08:05.557 に答える
1

イプシロンウィンドウでチェックするよりも少ないのはどうですか?aがbより小さい場合、aをbと等しくすることはできません

/**
 * checks whether a <= b with epsilon window
 */
template <typename T>
bool eq(T a, T b){
    T e = std::numeric_limits<T>::epsilon();
    return std::fabs(a-b) <= e;
}
/**
 * checks whether a < b with epsilon window
 */
template <typename T>
bool lt(T a, T b){
     if(!eq(a,b)){ // if a < b then a != b
         return a < b;
     }
     return false;
}
/**
 * checks whether a <= b with epsilon window
 */
template <typename T>
bool lte(T a, T b){
     if(eq(a,b)){
         return true;
     }
     return a < b;
}
于 2017-09-20T16:14:56.760 に答える