In C#, the result of Math.Round(2.5)
is 2.
It is supposed to be 3, isn't it? Is this a C# bug or something?
Thanks!
In C#, the result of Math.Round(2.5)
is 2.
It is supposed to be 3, isn't it? Is this a C# bug or something?
Thanks!
Firstly, this wouldn't be a C# bug anyway - it would be a .NET bug. C# is the language - it doesn't decide how Math.Round
is implemented.
And secondly, no - if you read the docs, you'll see that the default rounding is "round to even" (banker's rounding):
Return Value
Type: System.Double
The integer nearest a. If the fractional component of a is halfway between two integers, one of which is even and the other odd, then the even number is returned. Note that this method returns aDouble
instead of an integral type.Remarks
The behavior of this method follows IEEE Standard 754, section 4. This kind of rounding is sometimes called rounding to nearest, or banker's rounding. It minimizes rounding errors that result from consistently rounding a midpoint value in a single direction.
You can specify how Math.Round
should round mid-points using an overload which takes a MidpointRounding
value. There's one overload with a MidpointRounding
corresponding to each of the overloads which doesn't have one:
Round(Decimal)
/ Round(Decimal, MidpointRounding)
Round(Double)
/ Round(Double, MidpointRounding)
Round(Decimal, Int32)
/ Round(Decimal, Int32, MidpointRounding)
Round(Double, Int32)
/ Round(Double, Int32, MidpointRounding)
Whether this default was well chosen or not is a different matter. (MidpointRounding
was only introduced in .NET 2.0. Before then I'm not sure there was any easy way of implementing the desired behaviour without doing it yourself.) In particular, history has shown that it's not the expected behaviour - and in most cases that's a cardinal sin in API design. I can see why Banker's Rounding is useful... but it's still a surprise to many.
You may be interested to take a look at the nearest Java equivalent enum (RoundingMode
) which offers even more options. (It doesn't just deal with midpoints.)
From MSDN, Math.Round(double a) returns:
The integer nearest a. If the fractional component of a is halfway between two integers, one of which is even and the other odd, then the even number is returned.
... and so 2.5, being halfway between 2 and 3, is rounded down to the even number (2). this is called Banker's Rounding (or round-to-even), and is a commonly-used rounding standard.
Same MSDN article:
The behavior of this method follows IEEE Standard 754, section 4. This kind of rounding is sometimes called rounding to nearest, or banker's rounding. It minimizes rounding errors that result from consistently rounding a midpoint value in a single direction.
You can specify a different rounding behavior by calling the overloads of Math.Round that take a MidpointRounding
mode.
Really, documentation is your friend.
You should check MSDN for Math.Round
:
The behavior of this method follows IEEE Standard 754, section 4. This kind of rounding is sometimes called rounding to nearest, or banker's rounding.
You can specify the behavior of Math.Round
using an overload:
Math.Round(2.5, 0, MidpointRounding.AwayFromZero); // gives 3
Math.Round(2.5, 0, MidpointRounding.ToEven); // gives 2
Apparently the round method, when asked to round a number exactly between two integers, returns the even integer. So, Math.Round(3.5) returns 4.
See this article
How about this:
Math.Round(1123.485, 2, MidpointRounding.AwayFromZero)
gives the same result as
Math.Round(1123.485, 2, MidpointRounding.ToEven)
and that is 1123.48 :)
How logical is that?
This is ugly as all hell, but always produces correct arithmetic rounding.
public double ArithRound(double number,int places){
string numberFormat = "###.";
numberFormat = numberFormat.PadRight(numberFormat.Length + places, '#');
return double.Parse(number.ToString(numberFormat));
}
Any clues on which way rounding goes when using ToString()? E.g:
decimal a = 1.725m;
uxTB.Text = a.ToString("n");
uxTB.Text = a.ToString("c");
uxTB.Text = a.ToString("0.00");
etc.
I'm in a situation where I'm converting a site from "classic" ASP to ASP.Net and the old VBScript FormayNumber method has been used extensively, which rounds up, and I have been using Math.Round(a, 2) for financial figures until I came upon the "banker's rounding" outcome. The new app must look and work exactly like the old app, so I can't have £1.72 appearing where previously it was £1.73....
I'll be using the full-figured (snigger) decimal amounts (e.g. 1.725) for back-end calculations, and then rounding the outcomes as necessary, as they are financial amounts - I just need to impress this on the project sponsors I think, as they may want me to use Math.Ceiling instead...
EDIT: Why does Math.Round(1.725m, 2) return 1.72? The 2 is clearly between two odd numbers, yet the even number is returned. HAY-YELP!
Ta for any advice...
This has stung me before with writing reports for accounting, so I'll write a few words of what I found out, previously and from looking into it for this post.
From wikipedia
The origin of the term bankers' rounding remains more obscure. If this rounding method was ever a standard in banking, the evidence has proved extremely difficult to find. To the contrary, section 2 of the European Commission report The Introduction of the Euro and the Rounding of Currency Amounts suggests that there had previously been no standard approach to rounding in banking; and it specifies that "half-way" amounts should be rounded up.
It seems a very strange way of rounding particularly for banking, unless of course banks use to receive lots of deposits of even amounts. Deposit £2.4m, but we'll call it £2m sir.
The IEEE Standard 754 dates back to 1985 and gives both ways of rounding, but with banker's as the recommended by the standard. This wikipedia article has a long list of how languages implement rounding (correct me if any of the below are wrong) and most use school style rounding:
Return Value Type: System.Double The integer nearest a. If the fractional component of...
blah blah blah... Who reads this stuff anyway. After stumbling on Math.Round(2.5)==2 bug it took me few seconds to decide to write my own rounding function, and a minute to implement one. But of course I'm still baffled by how so widely used library allows such screw ups. If theoretical math says 2.5 rounded to integral number is 3, then it is. Period. No buts. End of file. :)
PS. value>=0 ? (int)(value+0.5) : -(int)(-value+0.5)