Why is System.MidpointRounding.AwayFromZero not rounded in this case?

In .NET, why does System.Math.Round(1.035, 2, MidpointRounding.AwayFromZero) give 1.03 instead of 1.04? I feel that the answer to my question lies in the “Note for Callers” section at http://msdn.microsoft.com/en-us/library/ef48waz8.aspx , but I cannot finish my head around the explanation.

+23
c #
Feb 10 2018-12-12T00:
source share
5 answers

Your suspicion is true. Fractional part numbers, expressed as literals in .NET, double by default. The double (like float) is the approximation of the decimal value, not the exact decimal value. This is the closest value that can be expressed in base-2 (binary). In this case, the approximation always disappears on the small side of 1.035. If you write it using an explicit decimal, it works as you would expect:

 Console.WriteLine(Math.Round(1.035m, 2, MidpointRounding.AwayFromZero)); Console.ReadKey(); 

To understand why doubles and floats work the way they do, imagine 1/3 in decimal (or binary, which suffers from the same problem). You can’t - this translates to .3333333 ...., which means that it needs an infinite amount of memory to represent it accurately.

Computers get around using approximations. I would definitely explain how, but I'm probably wrong. You can read all about it here: http://en.wikipedia.org/wiki/IEEE_754-1985

+26
Feb 10 2018-12-12T00:
source share

The binary representation 1.035d has the value 0x3FF08F5C28F5C28F, which is actually 1.03499999999999992006394222699E0, so System.Math.Round (1.035, 2, MidpointRounding.AwayFromZero) gives 1.03 instead of 1.04, so it is fixed.

However, the binary representation of 4.005d is 0x4010051EB851EB85, which is 4.00499999999999989341858963598, so System.Math.Round (4.005, 2, MidpointRounding.AwayFromZero) should give 4.00, but this gives 4.01, which is a wrong (or smart) fix "). its in MS SQL, select ROUND (CAST (4.005 AS float), 2), it is 4.00 I don’t understand why .NET is applying this “smart fix”, which makes the situation worse.

You can check the binary representation of double in: http://www.binaryconvert.com/convert_double.html

+8
Dec 14
source share

This is because the BINARY 1.035 view is closer to 1.03 than 1.04

For a better result, do it like this -

 decimal result = decimal.Round(1.035m, 2, MidpointRounding.AwayFromZero); 
+6
Feb 10 2018-12-12T00:
source share

I believe that the example you are talking about is another problem; As far as I understand, they say that 0.1 is not stored in the float, as exactly 0.1, it is actually a bit disabled due to the way the float is stored in binary format. So, suppose it actually looks more like 0.0999999999999 (or similar), something very, very slightly less than 0.1 - so insignificant that it doesn't really matter. Well, no, they say: one noticeable difference would be that adding this to your number and rounding would actually seem wrong, because although the numbers are very close, they are still considered "less." 5 for rounding.

If I misunderstood this page, I hope someone corrects me :)

I do not understand how this relates to your challenge, because you are more explicit. Perhaps it just stores your number in a similar way.

+3
Feb 10 2018-12-12T00:
source share

I guess I would say that internally 1.035 cannot be represented in binary exactly like 1.035, and probably (under the hood) 1.0349999999999999, and that is why it is rounded down.

Just a guess.

+1
Feb 10 2018-12-12T00:
source share



All Articles