Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Math.Round(2.5) return 2 instead of 3?

Tags:

.net

rounding

In C#, the result of Math.Round(2.5) is 2.

It is supposed to be 3, isn't it? Why is it 2 instead in C#?

like image 906
jeffu Avatar asked Jun 10 '09 19:06

jeffu


People also ask

What does 2.5 round to?

Both 1.5 and 2.5 are rounded to 2 . 3.5 and 4.5 are rounded to 4 . It prevents cumulative rounding errors and this is why it's often used in science (we use it as a default mode in our sig fig calculator.

What is 2.5 rounded to the nearest whole number?

Since, 2.5 being the decimal number, it is not considered to be a whole number. However, it can be converted to a whole number by rounding it off to the nearest whole number. 2.5 rounded off to the nearest whole number is 3. Hence, the whole number of 2.5 will be 3.

Why does 2.5 round down in Python?

The round() function rounding strategy and return type have changed. Exact halfway cases are now rounded to the nearest even result instead of away from zero. (For example, round(2.5) now returns 2 rather than 3.)

Do you round down at 3?

If the number you are rounding is followed by 0, 1, 2, 3, or 4, round the number down. Example: 33 rounded to the nearest ten is 30.


1 Answers

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 a Double 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.)

like image 132
Jon Skeet Avatar answered Oct 20 '22 12:10

Jon Skeet