3

I use the decimal type for high precise calculation (monetary).

But I came across this simple division today:

1 / (1 / 37) which should result in 37 again

http://www.wolframalpha.com/input/?i=1%2F+%281%2F37%29

But C# gives me: 37.000000000000000000000000037M

I tried both these: 1m/(1m/37m); and Decimal.Divide(1, Decimal.Divide(1, 37))

but both yield the same results. How is the behaviour explainable?

Szymon
  • 42,577
  • 16
  • 96
  • 114
Roger Far
  • 2,178
  • 3
  • 36
  • 67
  • More info: http://stackoverflow.com/questions/618535/what-is-the-difference-between-decimal-float-and-double-in-c?rq=1 – Jeroen Vannevel Oct 18 '13 at 03:50
  • I think you should look into http://msdn.microsoft.com/en-us/library/364x0z75.aspx - Decimal isn't going to take (1/37) and represent it as a numerator/denominator members. It's just a number with a larger size and smaller range, which makes it more appropriate for certain computation. The smaller range and larger size means that decimal has higher precision. – Warty Oct 18 '13 at 03:51
  • [What Every Programmer Should Know About Floating-Point Arithmetic](http://floating-point-gui.de/) – Brian Rogers Oct 18 '13 at 04:14

2 Answers2

5

Decimal stores the value as decimal floating point with only limited precision. The result of 1 / 37 is not precicely stored, as it's stored as 0.027027027027027027027027027M. The true number has the group 027 going indefinitely in decimal representation. For that reason, you cannot get the precise numbers in decimal representation for every possible number.

If you use Double in the same calculation, the end result is correct in this case (but it does not mean it will always be better).

A good answer on that topic is here: Difference between decimal, float and double in .NET?

Community
  • 1
  • 1
Szymon
  • 42,577
  • 16
  • 96
  • 114
1

Decimal data type has an accuracy of 28-29 significant digits. So what you have to understand is when you consider 28-29 significant digits you are still not exact.

So when you compute a decimal value for (1/37) what you have to note is that at this stage you are only getting an accuracy of 28-29 digits. e.g 1/37 is 0.02 when you take 2 significant digits and 0.027 when you take 3 significant digits. Imagine you divide 1 with these values in each case. you get a 50 in first case and in second case you get 37.02...Considering 28-29 digits (decimal ) takes you to an accuracy of 37.000000000000000000000000037. If you have to get an exact 37 you simply need more than 28-29 significant digits than the decimal offers.

Always do computations with maximum significant digits and round off only your answer with Math.Round for desired result.

simba
  • 463
  • 3
  • 6
  • 17
  • You say adding digits, but the result is infinite so would that even help? – Roger Far Oct 18 '13 at 04:26
  • When using decimal if you are not able to get an exact answer in 28-29 digits further calculations will have minute differences like you said. So with infinite results this is the closest you can get. – simba Oct 18 '13 at 04:39
  • I see yeah, I now added a `Decimal.Round(x, 5)` which yields ok results. – Roger Far Oct 18 '13 at 04:42