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?
The FLOOR function in Excel is used to round a given number down, to the nearest multiple of a specified significance. Number - the number you want to round. Significance - the multiple to which you wish to round the number. For example, =FLOOR(2.5, 2) rounds 2.5 down to the nearest multiple of 2, which is 2.
Round(Double, Int32, MidpointRounding) This method is used to rounds a double precision floating-point value to a specified number of fractional digits. A parameter specifies how to round the value if it is midway between two numbers.
If the number you are rounding is followed by 5, 6, 7, 8, or 9, round the number up. Example: 38 rounded to the nearest ten is 40. If the number you are rounding is followed by 0, 1, 2, 3, or 4, round the number down. Example: 33 rounded to the nearest ten is 30.
Round With no options, we use just one argument. This rounds the number to 123. And With a second argument of 1, we round to one decimal place. This yields the values 123.5 (for AwayFromZero) and 123.4 (for ToEven).
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 exactly
4.7249999999999996447286321199499070644378662109375
Keep 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.
Your value1
could easily be 4.724999999999999999999999999999999
. Why should it be rounded to to 4.73
instead of 4.72
?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With