Related
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#?
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 ValueType: System.DoubleThe 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.
RemarksThe 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.)
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).
Follow these links for the MSDN descriptions of:
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.
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
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.
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))
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.
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
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
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
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;
}
}
}
Source: http://anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/
Simple way is:
Math.Ceiling(decimal.Parse(yourNumber + ""));
Rounding numbers with .NET has the answer you are looking for.
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.
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);
}
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.
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));
}
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#?
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 ValueType: System.DoubleThe 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.
RemarksThe 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.)
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).
Follow these links for the MSDN descriptions of:
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.
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
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.
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))
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.
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
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
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
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;
}
}
}
Source: http://anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/
Simple way is:
Math.Ceiling(decimal.Parse(yourNumber + ""));
Rounding numbers with .NET has the answer you are looking for.
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.
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);
}
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.
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));
}
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#?
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 ValueType: System.DoubleThe 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.
RemarksThe 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.)
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).
Follow these links for the MSDN descriptions of:
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.
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
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.
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))
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.
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
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
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
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;
}
}
}
Source: http://anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/
Simple way is:
Math.Ceiling(decimal.Parse(yourNumber + ""));
Rounding numbers with .NET has the answer you are looking for.
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.
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);
}
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.
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));
}
while trying to parse variable to float with following parameter float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out fValue),
the value=6666.77777 is rounded of to 6666.778.
can anyone help, i don't want my value to be rounded.
float only has around 6 significant digits. Note that digits before the decimal point count too. double has higher precision in that regard (around 16):
PS> [float]::Parse('6666,77777')
6666.778
PS> [double]::Parse('6666,77777')
6666.77777
But as others noted, this is just an approximate value because it cannot be represented exactly in base 2. If you need decimal exactness (e.g. for money values) then use a decimal. For most other things binary floating point (i.e. float and double) should be fine.
Why don't you use Double.TryParse or Decimal.TryParse to support higher precision:
float: Approximately ±1.5 x 10-45 to ±3.4 x 1038 with 7 significant figures
double: Approximately ±5.0 x 10-324 to ±1.7 x 10308 with 15 or 16 significant figures
decimal: Approximately ±1.0 x 10-28 to ±7.9 x 1028 with 28 or 29 significant figures
Try this piece of code snippet instead:
double fValue;
double.TryParse("6666.77777", NumberStyles.Double, CultureInfo.InvariantCulture, out fValue);
OR
decimal fValue;
decimal.TryParse("6666.77777", NumberStyles.Decimal, CultureInfo.InvariantCulture, out fValue);
That is because value 666.77777 cannot be represented in the binary form floating point numbers use - the actual number contains more binary digits than the floating point has room for. The resulting number is the closest approximation.
Rounding is used when the exact result of a floating-point operation
(or a conversion to floating-point format) would need more digits than
there are digits in the significand. IEEE 754 requires correct
rounding: that is, the rounded result is as if infinitely precise
arithmetic was used to compute the value and then rounded (although in
implementation only three extra bits are needed to ensure this). There
are several different rounding schemes (or rounding modes).
Historically, truncation was the typical approach. Since the
introduction of IEEE 754, the default method (round to nearest, ties
to even, sometimes called Banker's Rounding) is more commonly used.
You should consider using double if you need more precision, or decimal if you need even more than that, though they too suffer from precision loss at some point.
you should use decimal if you need higher precision.
I am facing problem while rounding the decimal value in C# using Math.Round(a, 2);
When I'm rounding 1.275 by 2 decimal points, the result is 1.27.
When I'm doing the same for 1.375, the result is 1.38.
Why is it not rounding 1.275 to 1.28?
Thanks
I cannot reproduce your problem:
Math.Round(1.275m, 2) => 1.28m
Math.Round(1.375m, 2) => 1.38m
I suspect that your claim that you use a decimal value is false, and that you use double value instead. double can't represent many decimal values exactly, so when you write 1.275, it's actually 1.27499... 1.375 is one of the few representable onces, so it's actually 1.375.
If your code cares about exact decimal representation, for example when you work on money, you must use decimal and not binary floating point such as double or float.
But even if you use decimal representation, rounding behaves unexpectedly for many users:
Math.Round(1.265m, 2) => 1.26m
Math.Round(1.275m, 2) => 1.28m
By default Math.Round uses MidpointRounding.ToEven, also known as Banker's round. This avoids accumulating a bias from always rounding up at .5.
You can use an overload of Round that takes a rounding mode, and set it to AwayFromZero to get the behaviour you expect.
Math.Round(1.275m, 2, MidpointRounding.AwayFromZero) => 1.28m
MSDN has this to say regarding this behavior:
Notes to Callers
Because of the loss of precision that can result from
representing decimal values as floating-point numbers or performing
arithmetic operations on floating-point values, in some cases the
Round(Double, Int32) method may not appear to round midpoint values to
the nearest even value in the digits decimal position. This is
illustrated in the following example, where 2.135 is rounded to 2.13
instead of 2.14. This occurs because internally the method multiplies
value by 10digits, and the multiplication operation in this case
suffers from a loss of precision.
public class Example
{
public static void Main()
{
double[] values = { 2.125, 2.135, 2.145, 3.125, 3.135, 3.145 };
foreach (double value in values)
Console.WriteLine("{0} --> {1}", value, Math.Round(value, 2));
}
}
// The example displays the following output:
// 2.125 --> 2.12
// 2.135 --> 2.13
// 2.145 --> 2.14
// 3.125 --> 3.12
// 3.135 --> 3.14
// 3.145 --> 3.14
If you have a Decimal value, it will correctly round 1.275 to 1.28.
If you have a Double value, it will not behave the same, because the value 1.275 can not be represented exactly. If you use the double value 1.275, it will actually be slightly smaller than the exact value 1.275, something like 1.2749999999999999.
When rounding that value, it will not be exacly between 1.27 and 1.28 but slightly closer to 1.27, so it will be rounded down instead of up.
This is a terrible hack, but try using Format. It inexplicably uses the rounding we're all used to.
Val(Format(2.25, "0.0")) returns 2.3
(OR)
Just for information: From .Net version 2.0 its possible to define the way the "0.5 cases" are rounded with a parameter MidpointRounding. It can be either ToEven or AwayFromZero. So "standard" rounding would be like this:
Math.Round(2.25, 1, MidpointRounding.AwayFromZero);
This would return value "2.3".
Format(1.275, "0.00"))
as suggested in this blog's comments: http://weblogs.asp.net/sfurman/archive/2003/03/07/3537.aspx
Which version of the .Net framework do you use? If it is above 1.1, you can use the midpointrounding and set it to AwayFromZero
Math.Round(1.275, 2, MidpointRounding.AwayFromZero);
http://msdn.microsoft.com/en-us/library/9s0xa85y%28v=vs.110%29.aspx
It's because your rounding a double, and not a decimal:
Console.WriteLine(Math.Round(1.275M, 2)); // outputs 1.28
Console.WriteLine(Math.Round(1.375M, 2)); // outputs 1.38
Decimal and doubles are very different
Expected behaviour as per the documentation.
For example, if decimals is equal to 1, 2.15 and 2.15000 are both
rounded to 2.2 because .05 and .05000 are both halfway between .1 and
.2, and .1 is odd. Similarly, if decimals is equal to 1, 2.05 and
2.05000 are both rounded to 2.0 because .05 and .05000 are both halfway between .0 and .1, and .0 is even. 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. To control the type of
rounding used by the Round(Decimal, Int32) method, call the
Decimal.Round(Decimal, Int32, MidpointRounding) overload.
From Math.Round(decimal, int). Try
Decimal.Round(a, 2, MidpointRounding.AwayFromZero);