91

Sorry, this might be a easy stupid question, but I need to know to be sure.

I have this if expression,

void Foo()
{
    System.Double something = GetSomething();
    if (something == 0) //Comparison of floating point numbers with equality 
                     // operator. Possible loss of precision while rounding value
        {}
}

Is that expression equal with

void Foo()
{
    System.Double something = GetSomething();
    if (something < 1)
        {}
}

? Because then I might have a problem, entering the if with e.g. a value of 0.9.

radbyx
  • 8,605
  • 18
  • 75
  • 119

6 Answers6

117

Well, how close do you need the value to be to 0? If you go through a lot of floating point operations which in "infinite precision" might result in 0, you could end up with a result "very close" to 0.

Typically in this situation you want to provide some sort of epsilon, and check that the result is just within that epsilon:

if (Math.Abs(something) < 0.001)

The epsilon you should use is application-specific - it depends on what you're doing.

Of course, if the result should be exactly zero, then a simple equality check is fine.

Jon Skeet
  • 1,261,211
  • 792
  • 8,724
  • 8,929
  • Actually, I need it to be exactly zero, how would that look? I looked for Double.Zero, but know luck. There is a constant right? Btw, thanks, I get the epsilon part now :) – radbyx Jul 06 '11 at 15:42
  • 24
    @radbyx: Just use `== 0`. You've got a literal there - that's pretty constant :) – Jon Skeet Jul 06 '11 at 16:36
34

If something has been assigned from the result of an operation other than something = 0 then you better use:

if(Math.Abs(something) < Double.Epsilon)
{
//do something
}

Edit: This code is wrong. Epsilon is the smallest number, but not quite zero. When you wish to compare a number to another number, you need to think of what is the acceptable tolerance. Let's say that anything beyond .00001 you don't care about. That's the number you'd use. The value depends on the domain. However, it's mostly certainly never Double.Epsilon.

zumalifeguard
  • 7,799
  • 5
  • 31
  • 46
sonatique
  • 1,292
  • 12
  • 8
  • 2
    This doesn't solve the rounding problem, for example `Math.Abs(0.1f - 0.1d) < double.Epsilon` is `false` – Thomas Lulé Jan 08 '16 at 16:49
  • 6
    Double.Epsilon is too small for such comparsion. Double.Epsilon is the smallest positive number that double can represent. – Evgeni Nabokov Feb 27 '16 at 18:50
  • 3
    This makes no sense because it's practically the same as comparing against 0. -1 – Gaspa79 Apr 30 '17 at 05:30
  • 1
    The goal is to compare against the concept of 0 without using == . At least it makes sens mathematically. I am assuming you have a double at hand and you want to compare it to the concept of zero without ==. If your double is different from 0d for any reason, including rounding, the test fill return false. This comparison seems valid for any double and will return true only if this double is smallest than the smallest number that can be represented, which seems a good definition for testing the concept of 0, no? – sonatique May 01 '17 at 11:07
  • Nothing can be smaller than Double.Epsilon this expression is always false. – MaurGi May 08 '17 at 18:19
  • 4
    @MaurGi: you're wrong: `double d = Math.Sqrt(10100)*2; double a = Math.Sqrt(40400); if(Math.Abs(a - d) < double.Epsilon) { Console.WriteLine("true"); }` – sonatique May 13 '17 at 10:25
  • @sonatique Math.Abs(something) < Double.Epsilon evaluates to true only when something is exactly zero, in which case something == 0 would also be true, so why not just use that? – jonvw Jul 11 '17 at 21:02
  • 1
    "Because Epsilon defines the minimum expression of a positive value whose range is near zero, the margin of difference between two similar values must be greater than Epsilon. Typically, it is many times greater than Epsilon. Because of this, we recommend that you do not use Epsilon when comparing Double values for equality." https://msdn.microsoft.com/en-us/library/ya2zha7s.aspx – bleepzter Jan 17 '18 at 18:44
  • 1
    You should never use Double.Epsilon for double comparison. https://stackoverflow.com/questions/2411392/double-epsilon-for-equality-greater-than-less-than-less-than-or-equal-to-gre – nevermind Jun 07 '18 at 08:08
29

Your something is a double, and you have correctly identified that in the line

if (something == 0)

we have a double on the left-hand side (lhs) and an int on the right-hand side (rhs).

But now it seems like you think the lhs will be converted to an int, and then the == sign will compare two integers. That's not what happens. The conversion from double to int is explicit and can not happen "automatically".

Instead, the opposite happens. The rhs is converted to double, and then the == sign becomes an equality test between two doubles. This conversion is implicit (automatic).

It is considered better (by some) to write

if (something == 0.0)

or

if (something == 0d)

because then it's immediate that you're comparing two doubles. However, that's just a matter of style and readability because the compiler will do the same thing in any case.

It's also relevant, in some cases, to introduce a "tolerance" like in Jon Skeet's answer, but that tolerance would be a double too. It could of course be 1.0 if you wanted, but it does not have to be [the least strictly positive] integer.

Jeppe Stig Nielsen
  • 54,796
  • 9
  • 96
  • 154
17

If you simply want to suppress the warning, do this:

if (something.Equals(0.0))

Of course, this is only a valid solution if you know that drift isn't a concern. I often do this to check if I'm about to divide by zero.

Russell Phillips
  • 649
  • 5
  • 10
5

I dont' think it's equal, honestly. Consider yuor own example: something = 0.9, or 0.0004. In first case it will be FALSE, in second case it will be TRUE. Dealing with this types I usually define for me precision percentage and compare within that precision. Depends on your needs. something like...

if(((int)(something*100)) == 0) {


//do something
}

Hope this helps.

Tigran
  • 59,345
  • 8
  • 77
  • 117
3

Here is the example presenting the problem (prepared in LinQPad - if you don't have it just use Console.Writeline instead of Dump method):

void Main()
{
    double x = 0.000001 / 0.1;
    double y = 0.001 * 0.01; 

    double res = (x-y);
    res.Dump();
    (res == 0).Dump();
}

Both x and y are theoretically same and equal to: 0.00001 but because of lack of "infinite precision" those values are slightly different. Unfortunately slightly enough to return false when comparing to 0 in usual way.

michal-mad
  • 382
  • 3
  • 11