I stumbled across a method in my code where a rounded value is calculated wrong in my code.
I am aware about the problem with comparing double values generated unexpected results.
Example
double x = 19.08;
double y = 2.01;
double result = 21.09;
if (x + y == result)
{
// this is never reached
}
Explanation here: http://csharpindepth.com/Articles/General/FloatingPoint.aspx
However, until now, I expected the Math.Round() method to be accurate even with double values.
Look at this code.
var decimals = 2;
var value1 = 4.725;
var value2 = 4.725M;
var result1 = Math.Round(value1, decimals, MidpointRounding.ToEven);
var result2 = Math.Round(value1, decimals, MidpointRounding.AwayFromZero);
var result3 = Math.Round(value2, decimals, MidpointRounding.ToEven);
var result4 = Math.Round(value2, decimals, MidpointRounding.AwayFromZero);
Console.WriteLine("Double (ToEven): {0}", result1); // outputs 4.72
Console.WriteLine("Double (AwayFromZero): {0}", result2); // outputs 4.72 (expected: 4.73)
Console.WriteLine("Decimal (ToEven): {0}", result3); // outputs 4.72
Console.WriteLine("Decimal (AwayFromZero): {0}", result4); // outputs 4.73
For me, it is totally clear that result2 should be 4.73. However, it is not the case.
Can someone explain why?
Well, you may want to rethink your notion of »totally clear« because 4.725 (as opposed to 4.625) cannot be represented exactly with a
double. It’s actually exactlyKeep in mind that floating-point numbers are just an approximation to the mathematical concept of real numbers – many of your intuitive notions about how numbers should behave don’t apply. You end up with a value that is approximately 4.725 but obviously just slightly below it. The midpoint rounding mode will therefore do nothing here as it’s not exactly halfway between two possible numbers to round.