28

I have the following code:

double x = 0;

{ ...do stuff ...}

if(x == 0){

}

I was always taught that you shouldn't check floats for equality. Is checking to see if it is equal to zero any different?

dee-see
  • 23,668
  • 5
  • 58
  • 91
Steve
  • 4,457
  • 12
  • 48
  • 89
  • i don t understand, if you init x to 0 why it is not good to check if 0 ? 0 is a valid value for double – JohnJohnGa Aug 24 '11 at 19:15
  • 1
    Floating point numbers have a lot of rounding when you start to reach the limits. Same reason that if you have 3 digits to use in base ten, you have .004 and divide by three, you expect .001, but who knows what happens. – Ryan Amos Aug 24 '11 at 19:19
  • Thomas's corrections: It's technically not rounding, but inaccuracy due to the limited precision and the binary nature of floats. – Ryan Amos Aug 24 '11 at 19:29
  • Someone should summarize all the answers in this question. – SOFe Jul 11 '16 at 16:16

5 Answers5

33

The reason you shouldn't check floats for equality is that floating point numbers are not perfectly precise -- there's some inaccuracy in storage with some numbers, such as those that extended too far into the mantissa and repeating decimals (note that I'm talking about repeating decimals in base 2). You can think of this imprecision as "rounding down". The digits that extend beyond the precision of the floating-point number are truncated, effectively rounding down.

If it has not changed, it will keep that equality. However, if you change it even slightly, you probably should not use equalities, but instead a range like (x < 0.0001 && x > -.0001).

In short: as long as you're not playing with x at a very small level, it's OK.

Ryan Amos
  • 5,422
  • 4
  • 36
  • 56
  • 7
    It's not rounding that's going on, but the inability to store certain numbers due to the representation of floating point numbers. 0 can be exactly represented by a floating point value, but not all values can. 0.1, for example, has to be approximated. – Thomas Owens Aug 24 '11 at 19:18
  • 1
    @Thomas Rounding down. Same reason that `3/2` is `1` – Ryan Amos Aug 24 '11 at 19:20
  • 8
    No, not rounding. Imprecisions in IEEE floating point representations. Has absolutely nothing to do with rounding at all. http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems – Thomas Owens Aug 24 '11 at 19:21
  • Same thing @Thomas. Would you say `3/2` is `1` because of "imprecisions in the integer representations"? See [What Every Computer Scientist Should Know About Floating-Point Arithmetic](http://www.validlab.com/goldberg/paper.pdf) pg173, or [Wikipedia](http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding) – Museful Mar 20 '13 at 09:32
  • @tennenrishin it is due to imprecision, in a sense. 3/2= 1.5, but integer division is only precise up to the decimal point, making it 1. – Ryan Amos Mar 22 '13 at 18:15
  • 5
    Yeah, and it has absolutely nothing to do with rounding at all. Except that it is [called rounding](https://www.google.com/search?q=floating+point+rounding+error) (even [in the article](http://en.wikipedia.org/wiki/Floating_point#Representable_numbers.2C_conversion_and_rounding) linked by @Thomas). – Museful Aug 12 '13 at 17:34
  • Should I decrease the epsilon range if I know that the log10 of all my doubles are somewhere below, say, -5? – SOFe Jul 11 '16 at 16:14
  • Or should I compare the log rather than the absolute value of the numbers? – SOFe Jul 11 '16 at 16:29
  • @PEMapModder I'm not sure why that would help you? I suppose if you have the log handy you could, but I don't see any reason it would be better to use the log than the raw value. – Ryan Amos Aug 26 '16 at 16:42
17

It is safe if the 0 you're trying to catch is the original 0 set at initialization. However, it isn't safe if you're expecting a 0 from a mathematical operation.

dee-see
  • 23,668
  • 5
  • 58
  • 91
5

You still shouldn't check to see if it's equal to zero. Just check to see if it's near zero.

private final static double EPSILON = 0.00001;
if (x + EPSILON > 0 && x - EPSILON < 0){
...
}
WillHaack
  • 586
  • 3
  • 8
  • 19
  • 3
    You should not use an absolute epison but a relative one. E.G., `if (value >= target * (1 - epsilon) && value <= target * (1 + epsilon ))` This is especially true when the values can vary over a large range. – Hovercraft Full Of Eels Aug 24 '11 at 19:27
  • 2
    @HovercraftFullOfEels This will work only if target is positive. – Tanmay Patil Apr 22 '15 at 13:31
4

if you set it yourself and wish to see if it ever changed you can safely check for equality (like using a sentinel value) though NaN is safer for things like that

float x=Float.NaN;
{
   //some code that may or may not set x
}
if(Float.isNaN(x))//it never got set
ratchet freak
  • 47,288
  • 5
  • 68
  • 106
1

double has positive and negative zero. == between positive zero and negative zero returns false. Also, == betwen two NaNs returns false.

Evgeniy Dorofeev
  • 133,369
  • 30
  • 199
  • 275
  • You're wrong. Negative zero compares equal to positive zero. This is required by the IEEE-794 standard, which Java follows. – Sneftel Feb 13 '20 at 09:17