Comparing doubles can produce unexpected results

Well, guess what, smart people learn from other people’s mistakes and Kirill learns from his own.

This is actually a well-known caveat about doubles, but still a reminder about something to be aware of. A double value can be something else than you might think it is. For example, when you expect a double to be exactly 6, it could be 5.9999999999999991 and you will wonder, how on earth is it possible that 6 != 6:


The upper tooltip clearly shows that the second coordinate is 6, but comparing it with 6 fails. Whoa, the detailed view shows 5.9999999999999991.

What’s up with that? Luckily, the .NET framework source is easily available, so a quick look at Point.ToString() reveals that they simply format the output to round away the last couple of precision digits. The X and Y on the contrary are displayed unformatted (or should I say formatted less aggressively).

Under closer examination (and after half an hour of pulling my hair out) it looks like the system represented the calculation result as close to the decimal integer 6 it could, given the double precision in .NET encoded in binary. The failing code was comparing if (point.Y == 6) and the comparison failed against my expectations.

The solutioin for this is to test for the fact, “is the value within epsilon of the ideal value of 6”, like this: if (Math.Abs(point.Y – 6) < 0.00000001) …

I should have read more Eric back in school.

Comments (4)

  1. Nekresh says:

    I prefer to use Double.Epsilon instead of 0.00000001

  2. Good article, a lot of developers forget that a double is an approximate number.

  3. Kirill Osenkov says:

    Hi Nekresh – great point about the double.Epsilon – I didn’t know about this one. However after reading the documentation here,

    it looks like we shouldn’t use this one for comparison – it’s too small. Two numbers can be further apart from each other than double.Epsilon and still be good for my purposes.

    I experimented with precisions a little and found out that for my purposes (i.e. for algorithms that I use), 6 to 12 digits precision is a good constant.

    Your algorithms might be different, of course, so this might be perfectly valid for your goals.

  4. Thorn says:

    Hey, if you wrote "a = 6.0" and next compare "if (a == 6.0)", this must work exactly as expected! There is no "almost six" digit, even in CLR representation. All this "a – 6.0 < 0.0001" is ugly and doesn’t correspond to the "real knowledge" – just another trick "how to make it work on M$ platform". Pity…