浮点数,我可以信任多于/大于比较?

时间:2013-03-12 23:46:06

标签: c++ floating-point

假设我有两个浮点数,我想比较它们。如果一个大于另一个,程序应该采用一个分叉。如果情况恰恰相反,那么应采取另一条道路。并且它应该做同样的事情,如果被比较的值被轻微地推向一个应该仍然比较真实的方向。

这是一个难以回答的问题,所以我写这篇文章来证明它 -

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()保证永远不会被调用吗?

5 个答案:

答案 0 :(得分:11)

如果您可以保证ab不是NaN或无穷大,那么您可以这样做:

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

除了无穷大和NaN之外的所有浮点值的集合包括总排序(带有两个零表示的故障,但这对你来说无关紧要),这与使用普通整数集合没有什么不同 - 唯一的区别是后续值之间的间隔大小不是恒定的,就像整数一样。

事实上,IEEE 754的设计使得可以使用与正常整数相同的操作来比较相同符号的非NaN非无穷大值(同样,假设为零)。因此,在这种特定情况下,您可以将这些数字视为“更好的整数”。

答案 1 :(得分:4)

简短的回答,保证永远不会被召唤。

如果a<b则a总是小于b加上正数,不管多小。在这种情况下,测试a是否小于b +一个量将是真实的。

第三个案件未能达成。

答案 2 :(得分:2)

IEEE 754(浮点)标准规定加法或减法可导致正或负无穷大,因此如果b为FLT_MAX或-FLT_MAX,则b + FLOAT_EPSILON和b - FLOAT_EPSILON可导致正或负无穷大。浮点标准还指出无穷大比较你所期望的,FLT_MAX&lt; +无穷大返回true和-FLT_MAX&gt; -无穷。

从实用角度详细了解浮点格式和精度问题,我建议看一下Christer Ericson的书Real Time Collision Detection或Bruce Dawson关于这个主题的博客文章,其中最新的(有一个很好的)目录!)位于http://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/

答案 3 :(得分:2)

对不平等的测试是准确的,对平等的测试也是如此。人们感到困惑,因为他们没有意识到他们正在使用的价值可能不是他们认为的那样。所以,是的,最终函数调用的注释是正确的。那个分支永远不会被采用。

答案 4 :(得分:0)

与使用epsilon窗口检查相比,该怎么办?如果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;
}