Floating Point, how much can I trust less than / greater than comparisons?

别来无恙 提交于 2021-02-18 09:54:40

问题


Let's say I have two floating point numbers, and I want to compare them. If one is greater than the other, the program should take one fork. If the opposite is true, it should take another path. And it should do the same thing, if the value being compared is nudged very slightly in a direction that should still make it compare true.

It's a difficult question to phrase, so I wrote this to demonstrate it -

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
}

Given this code, is launchTheMissiles() guaranteed to never be called?


回答1:


If you can guarantee that a and b are not NaNs or infinities, then you can just do:

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

The set of all floating point values except for infinities and NaNs comprise a total ordering (with a glitch with two representations of zero, but that shouldn't matter for you), which is not unlike working with normal set of integers — the only difference is that the magnitude of intervals between subsequent values is not constant, like it is with integers.

In fact, the IEEE 754 has been designed so that comparisons of non-NaN non-infinity values of the same sign can be done with the same operations as normal integers (again, with a glitch with zero). So, in this specific case, you can think of these numbers as of “better integers”.




回答2:


Short answer, it is guaranteed never to be called.

If a<b then a will always be less than b plus a positive amount, however small. In which case, testing if a is less than b + an amount will be true.

The third case won't get reached.




回答3:


Tests for inequality are exact, as are tests for equality. People get confused because they don't realize that the values they are working with might not be exactly what they think they are. So, yes, the comment on the final function call is correct. That branch will never be taken.




回答4:


The IEEE 754 (floating point) standard states that addition or subtraction can result in a positive or negative infinity, so b + FLOAT_EPSILON and b - FLOAT_EPSILON can result in positive or negative infinity if b is FLT_MAX or -FLT_MAX. The floating point standard also states that infinity compares as you would expect, with FLT_MAX < +infinity returning true and -FLT_MAX > -infinity.

For a closer look at the floating point format and precision issues from a practical standpoint, I recommend taking a look at Christer Ericson's book Real Time Collision Detection or Bruce Dawson's blog posts on the subject, the latest of which (with a nice table of contents!) is at http://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/.




回答5:


What about less than check with an epsilon window ? if a is less than b then a can not be equal to 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;
}


来源:https://stackoverflow.com/questions/15374444/floating-point-how-much-can-i-trust-less-than-greater-than-comparisons

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!