ChatGPT解决这个技术问题 Extra ChatGPT

Why does .NET use banker's rounding as default?

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.

Rounding up is not "more natural." Nature has nothing to do with it. It's simply what you learned in gradeschool when you learned the concept of "rounding." Gradeschool lessons don't always paint a full picture.
@Rob And that's why it is more natural, even though it ain't correct
I don't understand, @Pacerier. I explained why it's not natural, and you say that's in fact why it is natural. How does my argument work against my conclusion, which is the opposite of yours? Things you've grown accustomed to might feel natural, and sometimes we figuratively say that something is "second nature," but that doesn't make them natural.
@Rob I'm saying it is natural, because it feels natural. You do know that there are 36 different objects with the same variable name natural right?
nature's defintely analogue so it's the wrong word to use; but this is being pedantic. Maybe 'usual' would be a better word to use.."what is the usual rounding that people do" > 0.5 goes to 1.0

O
Ostemar

The other answers with reasons why the Banker's algorithm (aka round half to even) is a good choice are quite correct. It does not suffer from negative or positive bias as much as the round half away from zero method over most reasonable distributions.

But the question was why .NET use Banker's actual rounding as default - and the answer is that Microsoft has followed the IEEE 754 standard. This is also mentioned in MSDN for Math.Round under Remarks.

Also note that .NET supports the alternative method specified by IEEE by providing the MidpointRounding enumeration. They could of course have provided more alternatives to solving ties, but they choose to just fulfill the IEEE standard.


So, why does IEEE 754 follow bankers rounding? This (still good) answer just passes the bucket.
@HenkHolterman Probably due to what is mentioned in the other answers (and as I summarized); it does not suffer (too much) from negative or positive bias and as such makes for a more resonable default for most distributions and problem domains.
@BrandonBarkley A Decimal or decimal is a floating point number, and IEEE 754 does include decimal floating point numbers.
@HenkHolterman : or one could ague that Microsoft passed the bucket
K
Kibbee

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.


assuming you have an flat distribution of odd and even inputs of course
+1 for better algorithm, although Ostemar has the actual answer (stackoverflow.com/questions/311696/…)
@Ian, I give that answer +1 as well. Anyway we can get the "accepted answer moved" Maybe the OP can do this. The actual answer to "why" it uses this method is half way down the page. Although I quite like the rep boost I get about once a week from this answer.
@Kibbee - thanks for pushing up my answer. I guess it's up to the OP to change the accepted answer as he sees fit?
-1 for stating it's a better algorithm. - Given a random sample of number using banker's rounding you will end up having more numbers at even positions than odd positions. - It is only after you average those numbers that you get again a similar spread to the original distribution. - However if you for example would plot this data in a scatter plot one might see artificial grouping.
c
casperOne

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.


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.
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 - i'd probably be a perfectionist if i was dealing with a billion dollars ;-)
@E.J. Brennan: It took you $40k to figure that out? I see problems like this all the time, rounding is cause #1, double/float normalization is cause #2, programmer error #3 - #3 can be immediately set to #1 if there are no predefined test cases. btw can you please put me in contact with your billionare client, i think i could find a few more $40k bugs in his system too! :D
@seanxe: Or if you'd seen Office Space. Seriously, whenever you see mysterious, tiny inaccuracies in money, solving the mystery of exactly how they are happening is almost always a good idea. It's possible you'll decide not to fix bugs, but knowing the underlying cause still has value. I bet many people who work with money are happy to notice even tiny inaccuracies.
I
Ian Ringrose

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”

Bankers rounding have the advantage that on average you will get the same result if you:

round a set of “invoice lines” before adding them up,

or add them up then round the total

Rounding before adding up saved a lot of work in the days before computers.

(In the UK when we went decimal banks would not deal with half pence, but for many years there was still a half pence coin and shop often had prices ending in half pence – so lots of rounding)


"Decimals are mostly used for money" ... and everything else that isn't an integer.
@JohnTyree, Not true most of the time a double/float is used when it is not an integer. see stackoverflow.com/questions/2545567/…
Wow. Ridiculous mistake on my part. Decmials, yes. Decimals, no. For posterity, I agree with the original sentiment here.
Bankers might like bankers' rounding, but bookkeepers might not be fans of it, they say that 0.005 difference should round lead to round up by 0.01, not depending whether it is odd or even number.
O
Omid Sadeghi

Use another overload of Round function like this:

decimal.Round(2.5m, 0,MidpointRounding.AwayFromZero)

It will output 3. And if you use

decimal.Round(2.5m, 0,MidpointRounding.ToEven)

you will get banker's rounding.


This doesn't answer the question of why Banker's Rounding was chosen as the default.