18

假设我有两个浮点数,我想比较它们。如果一个大于另一个,程序应该采用一个 fork。如果情况正好相反,它应该走另一条路。并且它应该做同样的事情,如果被比较的值在一个仍然应该使它比较真实的方向上被轻轻推动。

这是一个很难表达的问题,所以我写了这个来证明它 -

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

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

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

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

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

于 2013-03-12T23:56:26.347 回答
4

简短的回答,保证永远不会被调用。

如果a<b那么 a 将始终小于 b 加上一个正数,无论多么小。在这种情况下,测试 a 是否小于 b + a 量将是正确的。

第三种情况不会达成。

于 2013-03-12T23:50:37.733 回答
2

对不等式的测试是精确的,对等式的测试也是如此。人们感到困惑是因为他们没有意识到他们正在使用的价值观可能并不完全是他们认为的那样。所以,是的,对最终函数调用的评论是正确的。该分支将永远不会被占用。

于 2013-03-13T01:08:05.557 回答
2

IEEE 754(浮点)标准规定,加法或减法可导致正无穷或负无穷,因此如果 b 为 FLT_MAX 或 -FLT_MAX,则 b + FLOAT_EPSILON 和 b - FLOAT_EPSILON 可导致正无穷或负无穷。浮点标准还指出,无穷大的比较正如您所期望的那样,FLT_MAX < +infinity 返回 true 并且 -FLT_MAX > -infinity。

要从实际的角度仔细研究浮点格式和精度问题,我建议看一下 Christer Ericson 的书 Real Time Collision Detection 或 Bruce Dawson 关于该主题的博客文章,其中最新的(带有漂亮的目录!)位于http://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/

于 2013-03-13T00:08:37.817 回答
1

用 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;
}
于 2017-09-20T16:14:56.760 回答