开发者

Comparing Doubles in Visual Studio - a standard way to catch this?

开发者 https://www.devze.com 2022-12-13 16:45 出处:网络
Even experienced programmers write C# code like this sometimes: double x = 2.5; double y = 3; if (x + 0.5 == 3) {

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 kno开发者_开发知识库ws 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".


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...


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


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


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 :-)


Mono's Gendarme is an FxCop-like tool. It has a rule called AvoidFloatingPointEqualityRule under the Correctness category. You could try it to find instances of this error in your code. I haven't used it, but it should analyse regular .net dll's. The FxCop rule with the same name was removed long ago.

0

精彩评论

暂无评论...
验证码 换一张
取 消