Wednesday, June 01, 2005

 

Arithmetic Rounding in .Net

Quiz time: what is the value of test after the following code runs:


decimal test = decimal.Round(12.345m, 2);


12.35, right? No - imagine my surprise to find that it returns 12.34!!

It turns out that .Net employs a type of rounding called "banker's rounding". When the rounding logic encounters a midpoint (like the 5 in my example), rather than always rounding up, it rounds to then nearest even number.

Of course, in my situation, I needed the traditional "arithmetic rounding" which always goes up (or away from zero) when a midpoint is encountered. Finding no such feature in .Net, I wrote my own. If you see any bugs in it, let me know!


public static decimal ArithmeticRound (decimal d, int decimals)

{

decimal power = (decimal)Math.Pow(10, decimals);

// Note: converting to positive number before calculating rounding, so that we don't need separate logic for negative number handling

decimal floored = (decimal.Floor((Math.Abs(d) * power)) / power);

decimal result;

if (Math.Abs(d) >= floored + ((decimal)Math.Pow(10, - (decimals + 1)) * 5))

result = floored + (decimal)Math.Pow(10, -(decimals));

else

result = floored;

return result * Math.Sign(d);

}


BTW, .Net 2 provides an option on the Round function to use either type of rounding. See http://msdn2.microsoft.com/library/wxhaazw6(en-us,vs.80).aspx

Comments: Post a Comment

<< Home

This page is powered by Blogger. Isn't yours?