假设我有两个浮点数,我想比较它们。如果一个大于另一个,程序应该采用一个分叉。如果情况恰恰相反,那么应采取另一条道路。并且它应该做同样的事情,如果被比较的值被轻微地推向一个应该仍然比较真实的方向。
这是一个难以回答的问题,所以我写这篇文章来证明它 -
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()
保证永远不会被调用吗?
答案 0 :(得分:11)
如果您可以保证a
和b
不是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;
}