views:

85

answers:

4

Folks,

Even experienced programmers write C# code like this sometimes:

double x = 2.5;
double y = 3;
if (x + 0.5 == 3) {
    // this will never be executed
}

Basically, it's common knowledge that two doubles (or floats) can never be precisely equal to each other, because of the way the computer handles floating point arithmetic.

The problem is, everyone sort-of knows this, but code like this is still all over the place. It's just so easy to overlook.

Questions for you:

  • How have you dealt with this in your development organization?
  • Is this such a common thing that the compiler should be checking that we all should be screaming really loud for VS2010 to include a compile-time warning if someone is comparing two doubles/floats?

UPDATE: Folks, thanks for the comments. I want to clarify that I most certainly understand that the code above is incorrect. Yes, you never want to == compare doubles and floats. Instead, you should use epsilon-based comparison. That's obvious. The real question here is "how do you pinpoint the problem", not "how do you solve the technical issue".

+4  A: 

Floating point values certainly can be equal to each other, and in the case you've given they always will be equal. You should almost never compare for equality using equals, but you do need to understand why - and why the example you've shown isn't appropriate.

I don't think it's something the compiler should necessarily warn about, but you may want to see whether it's something FxCop can pick up on. I can't see it in the warning list, but it may be there somewhere...

Personally I'm reasonably confident that competent developers would be able to spot this in code review, but that does rely on you having a code review in place to start with. It also relies on your developers knowing when to use double and when to use decimal, which is something I've found often isn't the case...

Jon Skeet
I would +1 for the point (no pun intended) about decimal - but I've upvoted :-)
Phil Nash
+2  A: 
static int _yes = 0;
static int _no = 0;

static void Main(string[] args)
{
    for (int i = 0; i < 1000000; i++)
    {
        double x = 1;
        double y = 2;
        if (y - 1 == x)
        {
            _yes++;
        }
        else
        {
            _no++;
        }
    }
    Console.WriteLine("Yes: " + _yes);
    Console.WriteLine("No: " + _no);
    Console.Read();
}

Output

Yes: 1000000

No: 0

Paul Creasey
LOL :) 15 chars
Amarghosh
Fine, fine, fine. The point stands. I'll edit my code.
Alex
+2  A: 

In our organization we have a lot of financial calculations and we don't use float and double for such tasks. We use Decimal in .NET, BigDecimal in Java and Numeric in MSSQL to escape round-off errors.

This article describes the problem: What Every CS Should Know About floating-Point Arithmetic

alygin
I'm well aware of the solution to the problem. What I'm asking is "how to spot it better", not "how to solve it".
Alex
OK. I've rewrote my answer.
alygin
+1  A: 

If FxCop or similar (as Jon suggests) doesn't work out for you a more heavy handed approach might be to take a copy of the code - replace all instances of float or double with a class you've written that's somewhat similar to System.Double, except that you overload the == operator to generate a warning!

I don't know if this is feasible in practice as I've not tried it - but let us know if you do try :-)

Phil Nash