views:

427

answers:

8

I know we can't compare 2 floating point values using ==. We can only compare they are within some interval of each other. I know

if(val == 0.512)

is wrong due to errors inherent in floating point calculations and conversion to binary and should be

if (val in (0.512-epsilon, 0.512+epsilon))

But is 0 special? Can we compare floats exactly to 0? Or even that is incorrect? Particularly in the context of C# and Java?

double val = 0;
val = getVal();
if(val == 0)
+2  A: 

I would still recommend following the tolerance idiom and not compare to zero exactly.

duffymo
+12  A: 

Even though 0 has an exact representation, you can't rely on the result of a calculation using floats to be exactly 0. As you noted, this is due to floating point calculation and conversion issues.

So, you should test for 0 against your tolerance epsilon.

Oded
Pretty much all the replies advised me against special casing 0. Thank you! Accepting first one [in default order].
Fakrudeen
@Fakrudeen: default order s by score first, then random.
Joachim Sauer
+5  A: 

You can compare to zero if you assigned that variable zero. If you get zero from eg. a subtraction you can still get a very small number close to zero. eg.: 0.1-0.1 may evalute to something like 1e-9.

Calmarius
A: 

I don't think you can in general - the calculation that occurs in getVal() might logically result in zero but that dosn't mean it will return zero. If you explicilty return a zero to indicate some condition then the compare should always work but I don't think it would be best practice. I'd modify the function to return a status code and pass the value to be changed byref.

Jackson
+1  A: 

Because zero does have an exact representation, it is possible for a value to compare == to zero. If the variable you are testing was set by an assignment, or from a value typed in (like getVal in your example?), it could easily be zero. But if it was the result of a calculation, the chances of it being exactly zero are very small. This is made worse because ordinary decimal fractions like 0.2 do not have an exact representation in floating point. That's why it's best to use epsilon.

Peter Westlake
+6  A: 

Use the tolerance / ephsilon approach.

I just evaluated the following in Java, which mathematically results in zero:

1.0/5.0 + 1.0/5.0 - 1.0/10.0 - 1.0/10.0 - 1.0/10.0 - 1.0/10.0

and actually got

2.7755575615628914E-17
Bruno Rothgiesser
+1 for providing an actual example.
Joachim Sauer
+1  A: 

For comparison with err all you need to is.

// compare a and b with an ERR error.
if (Math.abs(a - b) <= ERR)

To compare with 0

// compare a and 0 with an ERR error.
if (Math.abs(a) <= ERR)
Peter Lawrey
A: 

In any non-trivial situation, you should really only use the tolerance approach. As noted, zero comparison is only accurate when you actually assigned it to zero.

Without repeating what other have said, I just want to emphasize the fact that using the tolerance approach is more future proof. What you once think is a simple assignment may involve actual arithmetic later. Using a naked comparison makes it painfully obscure to debug at a later date.

kizzx2