views:

96

answers:

6

Hello everyone.

I have a rounding issue inside of .Net.

I am rounding a 3 digit number down to two digits and it is causing some problems with one number.

If I try to round 34.425 to two decimal places it should round it to 34.43. I am using the roundawayfromzero option and it has worked for every number in the program except for this one so far.

The code Math.Round(34.425, 2, MidpointRounding.AwayFromZero) should equal 34.43 however, it equals 34.42.

If I try this with any other number it works fine.

Math.Round(34.435, 2, MidpointRounding.AwayFromZero) = 34.44

Math.Round(34.225, 2, MidpointRounding.AwayFromZero) = 34.23

Math.Round(34.465, 2, MidpointRounding.AwayFromZero) = 34.47

I just wanted to check to see if anyone has run into this problem before?

For right now I have fixed this problem by converting the number to a decimal. I have changed the code to this and it works fine now:

Math.Round(CDec(34.425), 2, MidpointRounding.AwayFromZero) = 34.43

I am just looking for a reason on why my old code did not work.

Thank you!

Updated the code to the correct AwayFromZero

+13  A: 

Floating point is never exact, 34.425 may have an internal represantation 34.4249999999999.. which will be rounded up to 34.42.

If you need exact representation for numbers use the decimal type.

codymanix
+1 for decimal suggestion
Robert Greiner
Thank you for the response. I guess my big question is why does this work for all of the other values?
Jeff
I would also have to agree with you if it was a variable. However, I was putting this value into the watch list as 34.425. So it should not be represented as 34.43499999... Is that correct in my assumption?
Jeff
@Jeff: It's because of the floating-point representation. Have a look at http://docs.sun.com/source/806-3568/ncg_goldberg.html for a primer in floating-point math. Basically, floats are stored in something like scientific notation, with a binary base/mantissa and an integer power of 2 exponent. Not all numbers can be represented accurately this way. A decimal, while it works like a float in most real-world arithmetic, uses a slightly different storage mechanism, which limits the range of storable values but drastically increases precision and accuracy within that range
KeithS
+1 although it could be [explained more precisely](http://csharpindepth.com/Articles/General/FloatingPoint.aspx)
MarkJ
It's exact representation is 34.4249999999999971578290569595992565155029296875
Chris Dunaway
+2  A: 

Slightly confused about whether you're actually using MidpointRounding.ToEven or MidpointRounding.AwayFromZero. If you are using ToEven as the first snippet indicates, this is expected behavior.

I edited the question sorry about the confusion.
Jeff
+1  A: 

Your assumptions and results are incorrect:

Math.Round(34.225, 2, MidpointRounding.ToEven) == 34.22
Math.Round(34.465, 2, MidpointRounding.ToEven) == 34.46

and

Math.Round(34.425, 2, MidpointRounding.ToEven) == 34.42

That's how it works, and that's what I get on my box. Rounding to even means just that, rounding up or down to get to the next even number at the decimal place of interest.

Michael Goldshteyn
Sorry I copied the wrong code. All of them should be AwayFromZero.
Jeff
+1  A: 

The code Math.Round(34.425, 2, MidpointRounding.ToEven) should equal 34.43 however, it equals 34.42.

Why? ToEven must make it 34.42 since 42 is even. Behaviour is correct.

Aliostad
+1  A: 

Your first example is correct, two of your other three are wrong. MidpointRounding.ToEven rounds to the nearest even number (in the last rounding place) so in the case of 34.425, that number is 2 which is even so it's rounded down. In the case of 34.435, the number is 3 which is odd, so it's rounded up to 34.44.

Your three examples (with ToEven) should result in:
34.435 -> 34.44
34.225 -> 34.22
34.465 -> 34.46

Rudu
A: 

I don't use vb.net, so my reasoning may be incorrect, but based on the names of your parameters MidpointRounding.ToEven, I would expect 34.425 to be rounded to 34.42; but I would also expect 34.225 to be rounded to 34.22 and 34.465 to 34.46. The rounding of numbers that end in 5 as in your examples is a matter of convention. The most usual convention is round to an even number, which I deduce your .ToEven parameter would be adopting.

In addition, I suspect you are encountering the binary/decimal rounding problem. Checking the binary representation of 34.425 comes out as 10010.011011....... When you take the computer storage and representation of a decimal number (byte, word, double word, quad word and negative/positive complement) into account this can result in you not rounding the number you thought you were.

To get the results you want, you should probably add 0.00001 to any digit ending in 5 before rounding.

Chris Walton