tags:

views:

844

answers:

6

I'm not seeing the result I expect with Math.Round.

return Math.Round(99.96535789, 2, MidpointRounding.ToEven); // returning 99.97

As I understand MidpointRounding.ToEven, the 5 in the thousandths position should cause the output to be 99.96. Is this not the case?

I even tried this, but it returned 99.97 as well:

return Math.Round(99.96535789 * 100, MidpointRounding.ToEven)/100;

What am I missing

Thanks!

+17  A: 

You're not actually at the midpoint. MidpointRounding.ToEven indicates that if you had the number 99.965, i.e., 99.96500000[etc.], then you would get 99.96. Since the number you're passing to Math.Round is above this midpoint, it's rounding up.

If you want your number to round down to 99.96, do this:

// this will round 99.965 down to 99.96
return Math.Round(Math.Truncate(99.96535789*1000)/1000, 2, MidpointRounding.ToEven);

And hey, here's a handy little function to do the above for general cases:

// This is meant to be cute;
// I take no responsibility for floating-point errors.
double TruncateThenRound(double value, int digits, MidpointRounding mode) {
    double multiplier = Math.Pow(10.0, digits + 1);
    double truncated = Math.Truncate(value * multiplier) / multiplier;
    return Math.Round(truncated, digits, mode);
}
Dan Tao
+7  A: 

It only rounds to 99.96 if you're on the midpoint itself, i.e. 99.965:

C:\temp>ipy
IronPython 2.6 Beta 2 (2.6.0.20) on .NET 2.0.50727.4927
Type "help", "copyright", "credits" or "license" for more information.
>>> import clr
>>> from System import Math, MidpointRounding
>>> Math.Round(99.9651, 2, MidpointRounding.ToEven)
99.97
>>> Math.Round(99.965, 2, MidpointRounding.ToEven)
99.96
>>> Math.Round(99.9649, 2, MidpointRounding.ToEven)
99.96
>>> Math.Round(99.975, 2, MidpointRounding.ToEven)
99.98
>>>
Vinay Sajip
+1 for using IronPython. Made me smile.
John Oxley
@Vinay, sorry for my edit I was wrong..
Charles Bretana
A: 

The midpoint rounding is looked at only if the value is between your two cases.

In your case, it's not "5", it's "535...", so it's greater than the midpoint, and routines to .96. To get the behavior your expecting, you'd need to trunctate to the third decimal point, THEN round using MidpointRounding.ToEven.

Reed Copsey
+4  A: 

The MidpointRounding value only comes into play when you're trying to round a value whose least significant digit is exactly 5. In other words, the value would have to be 99.965 to get your desired result. Since this is not the case here, you are simply observing the standard rounding mechanism. See the MSDN page for more info.

Noldorin
+2  A: 

Here's the results that shed some light on the subject:

Math.Round(99.96535789, 2, MidpointRounding.ToEven); // returning 99.97
Math.Round(99.965, 2, MidpointRounding.ToEven);      // returning 99.96
Math.Round(99.96500000, 2, MidpointRounding.ToEven); // returning 99.96

The midpoint is exactly 5 ... not 535789, not 499999.

Lee
A: 

Math.Round 'Rounds a decimal value to a specified number of fractional digits.' when rounding 99.96500000,2 rounds to 99.96 and 99.96500001 to 99.67. It rounds the full value.

rdkleine