24

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)
Fakrudeen
  • 5,778
  • 7
  • 44
  • 70
  • 1
    mathematical pedantry: it's epsilon, not ephsilon. good question, though. – Carl Mar 04 '10 at 16:52
  • 8
    Of course you can compare two floating point values using exact equality. For certain restricted purposes, it's not what you want to do, but saying you "can't" do it is nonsense, pure and simple, and prevents developers from learning about the actual semantics of floating-point. – Stephen Canon Mar 04 '10 at 20:01
  • 1
    @Carl: Thank you for the Greek pedantry! edited the post. I am so used to writing (U+0395) ε, I didn't know the exact spelling! – Fakrudeen Mar 05 '10 at 13:16
  • @Stephen: Could you please explain with references? You may want to add your explanation as an answer. You seem to imply that exact equality should be the norm [with interval comparison "For certain restricted purposes"]. I hope you already know about "What Every Computer Scientist Should Know About Floating-Point Arithmetic" http://www.validlab.com/goldberg/paper.pdf – Fakrudeen Mar 05 '10 at 14:28

8 Answers8

17

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.

Bart Kiers
  • 166,582
  • 36
  • 299
  • 288
Oded
  • 489,969
  • 99
  • 883
  • 1,009
14

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
  • 18,570
  • 18
  • 110
  • 157
13

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
b.roth
  • 9,421
  • 8
  • 37
  • 50
4

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
  • 4,894
  • 1
  • 26
  • 35
4

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
  • 525,659
  • 79
  • 751
  • 1,130
2

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

duffymo
  • 305,152
  • 44
  • 369
  • 561
0

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
  • 5,627
  • 2
  • 29
  • 48
0

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
  • 18,775
  • 14
  • 76
  • 83