简体   繁体   中英

Comparison to 0.0 with floating point values

When using floating point numbers, there can sometimes be rounding issues. Because of this, it is usually not recommended to compare the result of calculations with == or != and instead to use an appropriate bound like abs(ab)<1.0e-10 .

But would it be appropriate to use it to compare to 0.0 ?

Here is what I am talking about:

double foo(){
    //code which can return values that aren't 0.0
    //all returns are either literals or global variables defined with literals
    return 0.0;
}

Here f will always return either exactly 0.0 or a number that is unambiguously not 0.0 . Specifically, the numbers will all have magnitudes greater than 0.1 but less than 2.0 .

Will 0.0==foo() always be true if it returns 0.0 ? Is it possible for 0.0==foo() to be true if foo returns a value other than 0.0 ?

Up to std::numeric_limits::digits<float> you're safe. This is because the mantissa is integral type (usually platform-specific uint; which is then extended to a float by sign bit and exponent).

http://en.cppreference.com/w/cpp/types/numeric_limits/digits

It's perfectly correct in your case to use floating point equality == 0.0 .

It perfectly fits the intention of the function (return some value or 0.0 if it fails). Using any other epsilon is somehow arbitrary and require the knowledge of the range of correct values. If ever something went to change that could well be the range of values rather than 0, so testing == 0.0 is not less future proof than other solutions IMO.

The only problem I see is that some compilers will warn about suspiscious usage of equality (-Wfloat-equal)... That's as usefull as warning about int a,b,c; ...; c=a+b; int a,b,c; ...; c=a+b; because such instruction might possibly lead to problem (integer overflow and undefined behaviour). Curiously, I never saw the second warning.

So if you want to make usage of -Wall -Werror compiler options future proof, you might encode failure differently (with a negative value for example) and test for foo < 0.0 - until someone discover that floating point inequality might require a tolerance too and declare the construct as suspiscious.

If you return a literal 0.0 then yes, but it is generally not a good idea, because while that is true today, can you be sure that under maintenance or code reuse it will remain true. Better to code something that will work in a wider set of circumstances. In this case:

foo() < 0.1

will return false for all values you have specified. A more general solution is to test for sufficient proximity to zero:

static const EPSILON = 0.00001 ;
std::fabs( foo() - 0.0 ) < EPSILON ; 

It is better to use one of the above patterns, because it does not require foo() to make any guarantees about the precision of "zero".

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM