Question

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!

Was it helpful?

Solution

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);
}

OTHER TIPS

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
>>>

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.

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.

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.

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.

If it were me, I wouldn't use Math.Round(), because that is not what you are trying to accomplish.

This is what I would do:

double num = 99.96535789;
double percentage = Math.Floor(100 * num) / 100;  

Which is much easier to read and is more of a mathematical approach.
I multiply the number by 100, now I have 9996.535789.
Then floor it, which is distinctively different than rounding, to return the smallest integer closest to the number, to get 9996.
I then divide by 100 to get the required 99.96.

P.S.
Floor is the opposite of ceiling, which returns the largest integer closest to the number.
So, the ceiling of 9996.535789 is 9997.
Both are different than rounding to no decimal points, which actually returns the closest integer to the number, whether it's smaller or larger -- whichever is closest; that is why you were getting 99.97 when you used rounding.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top