# [.net] Why does Math.Round(2.5) return 2 instead of 3?

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#?

This question is related to `.net` `rounding`

using a custom rounding

``````public int Round(double value)
{
double decimalpoints = Math.Abs(value - Math.Floor(value));
if (decimalpoints > 0.5)
return (int)Math.Round(value);
else
return (int)Math.Floor(value);
}
``````

Silverlight doesn't support the MidpointRounding option. Here's an extension method for Silverlight that adds the MidpointRounding enum:

``````public enum MidpointRounding
{
ToEven,
AwayFromZero
}

public static class DecimalExtensions
{
public static decimal Round(this decimal d, MidpointRounding mode)
{
return d.Round(0, mode);
}

/// <summary>
/// Rounds using arithmetic (5 rounds up) symmetrical (up is away from zero) rounding
/// </summary>
/// <param name="d">A Decimal number to be rounded.</param>
/// <param name="decimals">The number of significant fractional digits (precision) in the return value.</param>
/// <returns>The number nearest d with precision equal to decimals. If d is halfway between two numbers, then the nearest whole number away from zero is returned.</returns>
public static decimal Round(this decimal d, int decimals, MidpointRounding mode)
{
if ( mode == MidpointRounding.ToEven )
{
return decimal.Round(d, decimals);
}
else
{
decimal factor = Convert.ToDecimal(Math.Pow(10, decimals));
int sign = Math.Sign(d);
return Decimal.Truncate(d * factor + 0.5m * sign) / factor;
}
}
}
``````

This post has the answer you are looking for:

http://weblogs.asp.net/sfurman/archive/2003/03/07/3537.aspx

Basically this is what it says:

Return Value

The number nearest value with precision equal to digits. If value is halfway between two numbers, one of which is even and the other odd, then the even number is returned. If the precision of value is less than digits, then value is returned unchanged.

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. If digits is zero, this kind of rounding is sometimes called rounding toward zero.

That's called rounding to even (or banker's rounding), which is a valid rounding strategy for minimizing accrued errors in sums `(MidpointRounding.ToEven)`. The theory is that, if you always round a 0.5 number in the same direction, the errors will accrue faster (round-to-even is supposed to minimize that) (a).

• `Math.Floor`, which rounds down towards negative infinity.
• `Math.Ceiling`, which rounds up towards positive infinity.
• `Math.Truncate`, which rounds up or down towards zero.
• `Math.Round`, which rounds to the nearest integer or specified number of decimal places. You can specify the behavior if it's exactly equidistant between two possibilities, such as rounding so that the final digit is even ("`Round(2.5,MidpointRounding.ToEven)`" becoming 2) or so that it's further away from zero ("`Round(2.5,MidpointRounding.AwayFromZero)`" becoming 3).

The following diagram and table may help:

``````-3        -2        -1         0         1         2         3
+--|------+---------+----|----+--|------+----|----+-------|-+
a                     b       c           d            e

a=-2.7  b=-0.5  c=0.3  d=1.5  e=2.8
======  ======  =====  =====  =====
Floor                    -3      -1      0      1      2
Ceiling                  -2       0      1      2      3
Truncate                 -2       0      0      1      2
Round(ToEven)            -3       0      0      2      3
Round(AwayFromZero)      -3      -1      0      2      3
``````

Note that `Round` is a lot more powerful than it seems, simply because it can round to a specific number of decimal places. All the others round to zero decimals always. For example:

``````n = 3.145;
a = System.Math.Round (n, 2, MidpointRounding.ToEven);       // 3.14
b = System.Math.Round (n, 2, MidpointRounding.AwayFromZero); // 3.15
``````

With the other functions, you have to use multiply/divide trickery to achieve the same effect:

``````c = System.Math.Truncate (n * 100) / 100;                    // 3.14
d = System.Math.Ceiling (n * 100) / 100;                     // 3.15
``````

(a) Of course, that theory depends on the fact that your data has an fairly even spread of values across the even halves (0.5, 2.5, 4.5, ...) and odd halves (1.5, 3.5, ...).

If all the "half-values" are evens (for example), the errors will accumulate just as fast as if you always rounded up.

Since Silverlight doesn't support the MidpointRounding option you have to write your own. Something like:

``````public double RoundCorrect(double d, int decimals)
{
double multiplier = Math.Pow(10, decimals);

if (d < 0)
multiplier *= -1;

return Math.Floor((d * multiplier) + 0.5) / multiplier;

}
``````

For the examples including how to use this as an extension see the post: .NET and Silverlight Rounding

#### The nature of rounding

Consider the task of rounding a number that contains a fraction to, say, a whole number. The process of rounding in this circumstance is to determine which whole number best represents the number you are rounding.

In common, or 'arithmetic' rounding, it is clear that 2.1, 2.2, 2.3 and 2.4 round to 2.0; and 2.6, 2.7, 2.8 and 2.9 to 3.0.

That leaves 2.5, which is no nearer to 2.0 than it is to 3.0. It is up to you to choose between 2.0 and 3.0, either would be equally valid.

For minus numbers, -2.1, -2.2, -2.3 and -2.4, would become -2.0; and -2.6, 2.7, 2.8 and 2.9 would become -3.0 under arithmetic rounding.

For -2.5 a choice is needed between -2.0 and -3.0.

Other forms of rounding

'Rounding up' takes any number with decimal places and makes it the next 'whole' number. Thus not only do 2.5 and 2.6 round to 3.0, but so do 2.1 and 2.2.

Rounding up moves both positive and negative numbers away from zero. Eg. 2.5 to 3.0 and -2.5 to -3.0.

'Rounding down' truncates numbers by chopping off unwanted digits. This has the effect of moving numbers towards zero. Eg. 2.5 to 2.0 and -2.5 to -2.0

In "banker's rounding" - in its most common form - the .5 to be rounded is rounded either up or down so that the result of the rounding is always an even number. Thus 2.5 rounds to 2.0, 3.5 to 4.0, 4.5 to 4.0, 5.5 to 6.0, and so on.

'Alternate rounding' alternates the process for any .5 between rounding down and rounding up.

'Random rounding' rounds a .5 up or down on an entirely random basis.

Symmetry and asymmetry

A rounding function is said to be 'symmetric' if it either rounds all numbers away from zero or rounds all numbers towards zero.

A function is 'asymmetric' if rounds positive numbers towards zero and negative numbers away from zero.. Eg. 2.5 to 2.0; and -2.5 to -3.0.

Also asymmetric is a function that rounds positive numbers away from zero and negative numbers towards zero. Eg. 2.5 to 3.0; and -2.5 to -2.0.

Most of time people think of symmetric rounding, where -2.5 will be rounded towards -3.0 and 3.5 will be rounded towards 4.0. (in C# `Round(AwayFromZero)`)

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
``````

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));

}
``````

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.

From MSDN:

By default, Math.Round uses MidpointRounding.ToEven. Most people are not familiar with "rounding to even" as the alternative, "rounding away from zero" is more commonly taught in school. .NET defaults to "Rounding to even" as it is statistically superior because it doesn't share the tendency of "rounding away from zero" to round up slightly more often than it rounds down (assuming the numbers being rounded tend to be positive.)

http://msdn.microsoft.com/en-us/library/system.math.round.aspx

I had this problem where my SQL server rounds up 0.5 to 1 while my C# application didn't. So you would see two different results.

Here's an implementation with int/long. This is how Java rounds.

``````int roundedNumber = (int)Math.Floor(d + 0.5);
``````

It's probably the most efficient method you could think of as well.

If you want to keep it a double and use decimal precision , then it's really just a matter of using exponents of 10 based on how many decimal places.

``````public double getRounding(double number, int decimalPoints)
{
double decimalPowerOfTen = Math.Pow(10, decimalPoints);
return Math.Floor(number * decimalPowerOfTen + 0.5)/ decimalPowerOfTen;
}
``````

You can input a negative decimal for decimal points and it's word fine as well.

``````getRounding(239, -2) = 200
``````

Simple way is:

``````Math.Ceiling(decimal.Parse(yourNumber + ""));
``````

The default `MidpointRounding.ToEven`, or Bankers' rounding (2.5 become 2, 4.5 becomes 4 and so on) 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.

#### Who are these bankers that are rounding down on even numbers (British bankers perhaps!)?

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 don't use Bankers' but the rounding you're taught at school:

• C/C++ round() from math.h rounds away from zero (not banker's rounding)
• Java Math.Round rounds away from zero (it floors the result, adds 0.5, casts to an integer). There's an alternative in BigDecimal
• Perl uses a similar way to C
• Javascript is the same as Java's Math.Round.

Here's the way i had to work it around :

``````Public Function Round(number As Double, dec As Integer) As Double
Dim decimalPowerOfTen = Math.Pow(10, dec)
If CInt(number * decimalPowerOfTen) = Math.Round(number * decimalPowerOfTen, 2) Then
Return Math.Round(number, 2, MidpointRounding.AwayFromZero)
Else
Return CInt(number * decimalPowerOfTen + 0.5) / 100
End If
End Function
``````

Trying with 1.905 with 2 decimals will give 1.91 as expected but `Math.Round(1.905,2,MidpointRounding.AwayFromZero)` gives 1.90! Math.Round method is absolutely inconsistent and unusable for most of the basics problems programmers may encounter. I have to check if `(int) 1.905 * decimalPowerOfTen = Math.Round(number * decimalPowerOfTen, 2)` cause i don not want to round up what should be round down.