tags:

views:

1848

answers:

4

According to the documentation, the decimal.Round method uses a round-to-even algorithm which is not common for most applications. So I always end up writing a custom function to do the more natural round-half-up algorithm:

public static decimal RoundHalfUp(this decimal d, int decimals)
{
    if (decimals < 0)
    {
        throw new ArgumentException("The decimals must be non-negative", "decimals");
    }

    decimal multiplier = (decimal)Math.Pow(10, decimals);
    decimal number = d * multiplier;

    if (decimal.Truncate(number) < number)
    {
        number += 0.5m;
    }
    return decimal.Round(number) / multiplier;
}

Does anybody know the reason behind this framework design decision? Is there any built-in implementation of the round-half-up algorithm into the framework? Or maybe some unmanaged Windows API?

It could be misleading for beginners that simply write decimal.Round(2.5m, 0) expecting 3 as a result but getting 2 instead.

+19  A: 

Probably because it's a better algorithm. Over the course of many roundings performed, you will average out that all .5's end up rounding equally up and down. This gives better estimations of actual results if you are for instance, adding a bunch of rounded numbers. I would say that even though it isn't what some may expect, it's probably the more correct thing to do.

Kibbee
assuming you have an flat distribution of odd and even inputs of course
jk
+22  A: 

While I cannot answer the question of "Why did Microsoft's Designers Choose this as the default?", I just want to point out that an extra function is unnecessary.

Math.Round allows you to specify a MidpointRounding:

  • ToEven
    • When a number is halfway between two others, it is rounded toward the nearest even number.
  • AwayFromZero
    • When a number is halfway between two others, it is rounded toward the nearest number that is away from zero.
Michael Stum
And as I've mentioned in related threads, make sure that you're consistent in your rounding - if you sometimes do rounding in the database, and sometimes in .net, you will have strange, one cent errors that will take you weeks to figure out.
chris
A client once paid me over $40,000 to track down an $0.11 rounding error between two numbers that were both just shy of 1 BILLION dollars; the $0.11 was due to a difference in the 8th digit rounding error between a mainframe and SQL Server. Talk about a perfectionist!
EJB
@EJB - i'd probably be a perfectionist if i was dealing with a billion dollars ;-)
seanxe
+4  A: 

I would expect 72.5, but the result is 72.4

I wouldn't.

Are you saying you'd round 2.444444444444444449 up to three? (If you were rounding to zero decimal places)

Will Dean
+5  A: 

Decimals are mostly used for money; banker’s rounding is common when working with money. Or you could say.

It is mostly bankers that need the decimal type; therefore it does “banker’s rounding”

Ian Ringrose