Is double Multiplication Broken in .NET?

C#.NetMath

C# Problem Overview


If I execute the following expression in C#:

double i = 10*0.69;

i is: 6.8999999999999995. Why?

I understand numbers such as 1/3 can be hard to represent in binary as it has infinite recurring decimal places but this is not the case for 0.69. And 0.69 can easily be represented in binary, one binary number for 69 and another to denote the position of the decimal place.

How do I work around this? Use the decimal type?

C# Solutions


Solution 1 - C#

Because you've misunderstood floating point arithmetic and how data is stored.

In fact, your code isn't actually performing any arithmetic at execution time in this particular case - the compiler will have done it, then saved a constant in the generated executable. However, it can't store an exact value of 6.9, because that value cannot be precisely represented in floating point point format, just like 1/3 can't be precisely stored in a finite decimal representation.

See if this article helps you.

Solution 2 - C#

> why doesn't the framework work around this and hide this problem from me and give me the > right answer,0.69!!!

Stop behaving like a dilbert manager, and accept that computers, though cool and awesome, have limits. In your specific case, it doesn't just "hide" the problem, because you have specifically told it not to. The language (the computer) provides alternatives to the format, that you didn't choose. You chose double, which has certain advantages over decimal, and certain downsides. Now, knowing the answer, you're upset that the downsides don't magically disappear.

As a programmer, you are responsible for hiding this downside from managers, and there are many ways to do that. However, the makers of C# have a responsibility to make floating point work correctly, and correct floating point will occasionally result in incorrect math.

So will every other number storage method, as we do not have infinite bits. Our job as programmers is to work with limited resources to make cool things happen. They got you 90% of the way there, just get the torch home.

Solution 3 - C#

> And 0.69 can easily be represented in > binary, one binary number for 69 and > another to denote the position of the > decimal place.

I think this is a common mistake - you're thinking of floating point numbers as if they are base-10 (i.e decimal - hence my emphasis).

So - you're thinking that there are two whole-number parts to this double: 69 and divide by 100 to get the decimal place to move - which could also be expressed as:
69 x 10 to the power of -2.

However floats store the 'position of the point' as base-2.

Your float actually gets stored as:
68999999999999995 x 2 to the power of some big negative number

This isn't as much of a problem once you're used to it - most people know and expect that 1/3 can't be expressed accurately as a decimal or percentage. It's just that the fractions that can't be expressed in base-2 are different.

Solution 4 - C#

> but why doesn't the framework work around this and hide this problem from me and give me the right answer,0.69!!!

Because you told it to use binary floating point, and the solution is to use decimal floating point, so you are suggesting that the framework should disregard the type you specified and use decimal instead, which is very much slower because it is not directly implemented in hardware.

A more efficient solution is to not output the full value of the representation and explicitly specify the accuracy required by your output. If you format the output to two decimal places, you will see the result you expect. However if this is a financial application decimal is precisely what you should use - you've seen Superman III (and Office Space) haven't you ;)

Note that it is all a finite approximation of an infinite range, it is merely that decimal and double use a different set of approximations. The advantage of decimal is it produces the same approximations that you would if you were performing the calculation yourself. For example if you calculated 1/3, you would eventually stop writing 3's when it was 'good enough'.

Solution 5 - C#

For the same reason that 1 / 3 in a decimal systems comes out as 0.3333333333333333333333333333333333333333333 and not the exact fraction, which is infinitely long.

Solution 6 - C#

To work around it (e.g. to display on screen) try this:

double i = (double) Decimal.Multiply(10, (Decimal) 0.69);

Everyone seems to have answered your first question, but ignored the second part.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDanView Question on Stackoverflow
Solution 1 - C#Jon SkeetView Answer on Stackoverflow
Solution 2 - C#Russell SteenView Answer on Stackoverflow
Solution 3 - C#KeithView Answer on Stackoverflow
Solution 4 - C#CliffordView Answer on Stackoverflow
Solution 5 - C#erikkallenView Answer on Stackoverflow
Solution 6 - C#RichardView Answer on Stackoverflow