In C#, the result of Math.Round(2.5)
is 2.
在C#中,Math.Round(2.5)的结果为2。
It is supposed to be 3, isn't it? Why is it 2 instead in C#?
应该是3,不是吗?为什么它在C#中代替2?
15 个解决方案
#1
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.
首先,这不会是一个C#错误 - 它将是一个.NET错误。 C#是语言 - 它不决定如何实现Math.Round。
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.返回值类型:System.Double最接近a的整数。如果a的小数分量在两个整数之间,其中一个是偶数而另一个是奇数,则返回偶数。请注意,此方法返回Double而不是整数类型。
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.备注此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。它最大限度地减少了在单一方向上始终舍入中点值所导致的舍入误差。
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:
您可以指定Math.Round如何使用带有MidpointRounding值的重载来舍入中间点。有一个带有MidpointRounding的重载对应于每个没有一个的重载:
-
Round(Decimal)
/Round(Decimal, MidpointRounding)
-
Round(Double)
/Round(Double, MidpointRounding)
-
Round(Decimal, Int32)
/Round(Decimal, Int32, MidpointRounding)
-
Round(Double, Int32)
/Round(Double, Int32, MidpointRounding)
Round(Decimal)/ Round(Decimal,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.
是否选择此默认值是另一回事。 (MidpointRounding仅在.NET 2.0中引入。在此之前,我不确定是否有任何简单的方法可以实现所需的行为,而无需自己动手。)特别是,历史表明它不是预期的行为 - 并且在大多数情况下这是API设计中的主要罪魁祸首。我可以看出为什么Banker的Rounding很有用......但对许多人来说仍然是一个惊喜。
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.)
您可能有兴趣看一下最近的Java等效枚举(RoundingMode),它提供了更多选项。 (它不只是处理中点。)
#2
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).
这被称为舍入到均匀(或银行家的舍入),这是一种有效的舍入策略,用于最小化累计误差(MidpointRounding.ToEven)。理论上说,如果你总是在同一方向上对0.5的数字进行舍入,那么错误将会更快地产生(圆形到偶数应该最小化)(a)。
Follow these links for the MSDN descriptions of:
请按照以下链接获取MSDN描述:
-
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).
Math.Floor,向下舍入负无穷大。
Math.Ceiling,向正无穷大四舍五入。
Math.Truncate,向上或向下舍入为零。
Math.Round,舍入到最接近的整数或指定的小数位数。如果它在两种可能性之间完全等距,你可以指定行为,例如舍入使得最后的数字是偶数(“Round(2.5,MidpointRounding.ToEven)”变为2)或者它更远离零(“Round(2.5) ,MidpointRounding.AwayFromZero)“成为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 2Ceiling -2 0 1 2 3Truncate -2 0 0 1 2Round(ToEven) -3 0 0 2 3Round(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:
请注意,Round比它看起来更强大,只是因为它可以舍入到特定的小数位数。所有其他的总是小数点零。例如:
n = 3.145;a = System.Math.Round (n, 2, MidpointRounding.ToEven); // 3.14b = 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.14d = 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, ...).
(a)当然,这个理论取决于你的数据在偶数半部分(0.5,2.5,4.5,...)和奇数半部分(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.
如果所有“半值”都是平均值(例如),则错误将像您总是向上舍入一样快地累积。
#3
From MSDN, Math.Round(double a) returns:
从MSDN,Math.Round(double a)返回:
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.
最接近a的整数。如果a的小数分量在两个整数之间,其中一个是偶数而另一个是奇数,则返回偶数。
... 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.
......等于2.5,介于2和3之间,向下舍入到偶数(2)。这被称为Banker's Rounding(或round-to-even),是一种常用的舍入标准。
Same MSDN article:
相同的MSDN文章:
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.
此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。它最大限度地减少了在单一方向上始终舍入中点值所导致的舍入误差。
You can specify a different rounding behavior by calling the overloads of Math.Round that take a MidpointRounding
mode.
您可以通过调用采用MidpointRounding模式的Math.Round重载来指定不同的舍入行为。
#4
You should check MSDN for Math.Round
:
您应该检查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.
此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。
You can specify the behavior of Math.Round
using an overload:
您可以使用重载指定Math.Round的行为:
Math.Round(2.5, 0, MidpointRounding.AwayFromZero); // gives 3Math.Round(2.5, 0, MidpointRounding.ToEven); // gives 2
#5
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.
通常,或“算术”舍入,很明显2.1,2.2,2.3和2.4舍入到2.0;和2.6,2.7,2.8和2.9到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.
离开2.5,它不接近2.0而不是3.0。您可以在2.0和3.0之间进行选择,两者都同样有效。
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.
对于负数,-2.1,-2.2,-2.3和-2.4,将变为-2.0;在算术舍入下,-2.6,2.7,2.8和2.9将变为-3.0。
For -2.5 a choice is needed between -2.0 and -3.0.
对于-2.5,需要在-2.0和-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'取任意小数位数,并使其成为下一个'整数'。因此,不仅2.5和2.6轮到3.0,而2.1和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.
四舍五入将正数和负数从零移开。例如。 2.5至3.0和-2.5至-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
'舍入'通过砍掉不需要的数字来截断数字。这具有将数字移向零的效果。例如。 2.5到2.0和-2.5到-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.
在“银行家的舍入”中 - 以其最常见的形式 - 要舍入的.5向上或向下舍入,以便舍入的结果始终为偶数。因此2.5轮到2.0,3.5到4.0,4.5到4.0,5.5到6.0,依此类推。
'Alternate rounding' alternates the process for any .5 between rounding down and rounding up.
'替代舍入'在舍入和舍入之间交替任何.5的过程。
'Random rounding' rounds a .5 up or down on an entirely random basis.
'随机舍入'在完全随机的基础上上下调整.5。
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.
如果将正数向零和向负数除以零,则函数是“非对称的”。例如。 2.5到2.0;和-2.5到-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.
非对称性是将正数从零和负数向零舍入的函数。例如。 2.5至3.0;和-2.5到-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)
)
大多数时候人们会想到对称的舍入,其中-2.5将向-3.0舍入,3.5将向4.0舍入。 (在C#Round(AwayFromZero))
#6
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.
默认的MidpointRounding.ToEven,或者银行家的四舍五入(2.5变成2,4.5变成4等等)在写会计报告之前就已经惹我生气了所以我会先写一些我以前发现过的话,然后再看看进入这篇文章。
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.
银行家四舍五入这一术语的起源仍然较为模糊。如果这种舍入方法曾经是银行业的标准,那么事实证明很难找到证据。相反,欧盟委员会报告“欧元的引入和货币金额的四舍五入”第2节表明,以前没有标准的方法来进行银行业务的四舍五入;并指明应将“中途”金额四舍五入。
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.
这似乎是一种非常奇怪的四舍五入的方式,特别是对于银行业务,除非银行当然用来接收大量的偶数存款。存款240万英镑,但我们称之为200万英镑先生。
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:
IEEE标准754可以追溯到1985年,它提供了两种舍入方式,但是银行家是标准推荐的方式。这篇*文章列出了一个很长的列表,列出了语言如何实现四舍五入(如果以下任何一个错误,请纠正我),大多数人不使用银行家,但是你在学校教授的四舍五入:
- 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.
来自math.h的C / C ++ round()从零开始(不是银行家的舍入)
Java Math.Round从零开始舍入(它将结果置于底层,添加0.5,转换为整数)。 BigDecimal中有另一种选择
Perl使用与C类似的方式
Javascript与Java的Math.Round相同。
#7
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.)
默认情况下,Math.Round使用MidpointRounding.ToEven。大多数人不熟悉“四舍五入”作为替代方案,“从零开始四舍五入”更常见于学校。 .NET默认为“舍入到均匀”,因为它在统计上更优越,因为它不具有“从零舍入”的倾向,而是比向下舍入更频繁地舍入(假设舍入的数字往往是正数)。 )
http://msdn.microsoft.com/en-us/library/system.math.round.aspx
#8
Since Silverlight doesn't support the MidpointRounding option you have to write your own. Something like:
由于Silverlight不支持MidpointRounding选项,因此您必须自己编写。就像是:
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
有关如何将其用作扩展的示例,请参阅帖子:.NET和Silverlight Rounding
#9
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.
我有这个问题,我的SQL服务器向上舍入0.5比1,而我的C#应用程序没有。所以你会看到两个不同的结果。
Here's an implementation with int/long. This is how Java rounds.
这是一个int / long的实现。这就是Java的结果。
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.
如果你想保持它是一个双倍并使用小数精度,那么它实际上只是根据小数位数使用10的指数。
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
#10
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.
此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。如果数字为零,则这种舍入有时称为向零舍入。
#11
Silverlight doesn't support the MidpointRounding option. Here's an extension method for Silverlight that adds the MidpointRounding enum:
Silverlight不支持MidpointRounding选项。这是Silverlight的扩展方法,它添加了MidpointRounding枚举:
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/
#12
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);}
#13
Simple way is:
简单的方法是:
Math.Ceiling(decimal.Parse(yourNumber + ""));
#14
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 IfEnd 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.
尝试使用带有2位小数的1.905将得到1.91,但是Math.Round(1.905,2,MidpointRounding.AwayFromZero)得到1.90!对于程序员可能遇到的大多数基本问题,Math.Round方法绝对不一致且无法使用。我必须检查if(int)1.905 * decimalPowerOfTen = Math.Round(number * decimalPowerOfTen,2)因为我不想围绕应该舍入的内容。
#15
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));}
#1
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.
首先,这不会是一个C#错误 - 它将是一个.NET错误。 C#是语言 - 它不决定如何实现Math.Round。
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.返回值类型:System.Double最接近a的整数。如果a的小数分量在两个整数之间,其中一个是偶数而另一个是奇数,则返回偶数。请注意,此方法返回Double而不是整数类型。
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.备注此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。它最大限度地减少了在单一方向上始终舍入中点值所导致的舍入误差。
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:
您可以指定Math.Round如何使用带有MidpointRounding值的重载来舍入中间点。有一个带有MidpointRounding的重载对应于每个没有一个的重载:
-
Round(Decimal)
/Round(Decimal, MidpointRounding)
-
Round(Double)
/Round(Double, MidpointRounding)
-
Round(Decimal, Int32)
/Round(Decimal, Int32, MidpointRounding)
-
Round(Double, Int32)
/Round(Double, Int32, MidpointRounding)
Round(Decimal)/ Round(Decimal,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.
是否选择此默认值是另一回事。 (MidpointRounding仅在.NET 2.0中引入。在此之前,我不确定是否有任何简单的方法可以实现所需的行为,而无需自己动手。)特别是,历史表明它不是预期的行为 - 并且在大多数情况下这是API设计中的主要罪魁祸首。我可以看出为什么Banker的Rounding很有用......但对许多人来说仍然是一个惊喜。
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.)
您可能有兴趣看一下最近的Java等效枚举(RoundingMode),它提供了更多选项。 (它不只是处理中点。)
#2
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).
这被称为舍入到均匀(或银行家的舍入),这是一种有效的舍入策略,用于最小化累计误差(MidpointRounding.ToEven)。理论上说,如果你总是在同一方向上对0.5的数字进行舍入,那么错误将会更快地产生(圆形到偶数应该最小化)(a)。
Follow these links for the MSDN descriptions of:
请按照以下链接获取MSDN描述:
-
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).
Math.Floor,向下舍入负无穷大。
Math.Ceiling,向正无穷大四舍五入。
Math.Truncate,向上或向下舍入为零。
Math.Round,舍入到最接近的整数或指定的小数位数。如果它在两种可能性之间完全等距,你可以指定行为,例如舍入使得最后的数字是偶数(“Round(2.5,MidpointRounding.ToEven)”变为2)或者它更远离零(“Round(2.5) ,MidpointRounding.AwayFromZero)“成为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 2Ceiling -2 0 1 2 3Truncate -2 0 0 1 2Round(ToEven) -3 0 0 2 3Round(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:
请注意,Round比它看起来更强大,只是因为它可以舍入到特定的小数位数。所有其他的总是小数点零。例如:
n = 3.145;a = System.Math.Round (n, 2, MidpointRounding.ToEven); // 3.14b = 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.14d = 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, ...).
(a)当然,这个理论取决于你的数据在偶数半部分(0.5,2.5,4.5,...)和奇数半部分(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.
如果所有“半值”都是平均值(例如),则错误将像您总是向上舍入一样快地累积。
#3
From MSDN, Math.Round(double a) returns:
从MSDN,Math.Round(double a)返回:
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.
最接近a的整数。如果a的小数分量在两个整数之间,其中一个是偶数而另一个是奇数,则返回偶数。
... 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.
......等于2.5,介于2和3之间,向下舍入到偶数(2)。这被称为Banker's Rounding(或round-to-even),是一种常用的舍入标准。
Same MSDN article:
相同的MSDN文章:
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.
此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。它最大限度地减少了在单一方向上始终舍入中点值所导致的舍入误差。
You can specify a different rounding behavior by calling the overloads of Math.Round that take a MidpointRounding
mode.
您可以通过调用采用MidpointRounding模式的Math.Round重载来指定不同的舍入行为。
#4
You should check MSDN for Math.Round
:
您应该检查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.
此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。
You can specify the behavior of Math.Round
using an overload:
您可以使用重载指定Math.Round的行为:
Math.Round(2.5, 0, MidpointRounding.AwayFromZero); // gives 3Math.Round(2.5, 0, MidpointRounding.ToEven); // gives 2
#5
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.
通常,或“算术”舍入,很明显2.1,2.2,2.3和2.4舍入到2.0;和2.6,2.7,2.8和2.9到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.
离开2.5,它不接近2.0而不是3.0。您可以在2.0和3.0之间进行选择,两者都同样有效。
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.
对于负数,-2.1,-2.2,-2.3和-2.4,将变为-2.0;在算术舍入下,-2.6,2.7,2.8和2.9将变为-3.0。
For -2.5 a choice is needed between -2.0 and -3.0.
对于-2.5,需要在-2.0和-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'取任意小数位数,并使其成为下一个'整数'。因此,不仅2.5和2.6轮到3.0,而2.1和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.
四舍五入将正数和负数从零移开。例如。 2.5至3.0和-2.5至-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
'舍入'通过砍掉不需要的数字来截断数字。这具有将数字移向零的效果。例如。 2.5到2.0和-2.5到-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.
在“银行家的舍入”中 - 以其最常见的形式 - 要舍入的.5向上或向下舍入,以便舍入的结果始终为偶数。因此2.5轮到2.0,3.5到4.0,4.5到4.0,5.5到6.0,依此类推。
'Alternate rounding' alternates the process for any .5 between rounding down and rounding up.
'替代舍入'在舍入和舍入之间交替任何.5的过程。
'Random rounding' rounds a .5 up or down on an entirely random basis.
'随机舍入'在完全随机的基础上上下调整.5。
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.
如果将正数向零和向负数除以零,则函数是“非对称的”。例如。 2.5到2.0;和-2.5到-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.
非对称性是将正数从零和负数向零舍入的函数。例如。 2.5至3.0;和-2.5到-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)
)
大多数时候人们会想到对称的舍入,其中-2.5将向-3.0舍入,3.5将向4.0舍入。 (在C#Round(AwayFromZero))
#6
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.
默认的MidpointRounding.ToEven,或者银行家的四舍五入(2.5变成2,4.5变成4等等)在写会计报告之前就已经惹我生气了所以我会先写一些我以前发现过的话,然后再看看进入这篇文章。
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.
银行家四舍五入这一术语的起源仍然较为模糊。如果这种舍入方法曾经是银行业的标准,那么事实证明很难找到证据。相反,欧盟委员会报告“欧元的引入和货币金额的四舍五入”第2节表明,以前没有标准的方法来进行银行业务的四舍五入;并指明应将“中途”金额四舍五入。
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.
这似乎是一种非常奇怪的四舍五入的方式,特别是对于银行业务,除非银行当然用来接收大量的偶数存款。存款240万英镑,但我们称之为200万英镑先生。
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:
IEEE标准754可以追溯到1985年,它提供了两种舍入方式,但是银行家是标准推荐的方式。这篇*文章列出了一个很长的列表,列出了语言如何实现四舍五入(如果以下任何一个错误,请纠正我),大多数人不使用银行家,但是你在学校教授的四舍五入:
- 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.
来自math.h的C / C ++ round()从零开始(不是银行家的舍入)
Java Math.Round从零开始舍入(它将结果置于底层,添加0.5,转换为整数)。 BigDecimal中有另一种选择
Perl使用与C类似的方式
Javascript与Java的Math.Round相同。
#7
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.)
默认情况下,Math.Round使用MidpointRounding.ToEven。大多数人不熟悉“四舍五入”作为替代方案,“从零开始四舍五入”更常见于学校。 .NET默认为“舍入到均匀”,因为它在统计上更优越,因为它不具有“从零舍入”的倾向,而是比向下舍入更频繁地舍入(假设舍入的数字往往是正数)。 )
http://msdn.microsoft.com/en-us/library/system.math.round.aspx
#8
Since Silverlight doesn't support the MidpointRounding option you have to write your own. Something like:
由于Silverlight不支持MidpointRounding选项,因此您必须自己编写。就像是:
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
有关如何将其用作扩展的示例,请参阅帖子:.NET和Silverlight Rounding
#9
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.
我有这个问题,我的SQL服务器向上舍入0.5比1,而我的C#应用程序没有。所以你会看到两个不同的结果。
Here's an implementation with int/long. This is how Java rounds.
这是一个int / long的实现。这就是Java的结果。
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.
如果你想保持它是一个双倍并使用小数精度,那么它实际上只是根据小数位数使用10的指数。
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
#10
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.
此方法的行为遵循IEEE标准754第4节。这种舍入有时称为舍入到最近,或者是银行家的舍入。如果数字为零,则这种舍入有时称为向零舍入。
#11
Silverlight doesn't support the MidpointRounding option. Here's an extension method for Silverlight that adds the MidpointRounding enum:
Silverlight不支持MidpointRounding选项。这是Silverlight的扩展方法,它添加了MidpointRounding枚举:
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/
#12
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);}
#13
Simple way is:
简单的方法是:
Math.Ceiling(decimal.Parse(yourNumber + ""));
#14
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 IfEnd 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.
尝试使用带有2位小数的1.905将得到1.91,但是Math.Round(1.905,2,MidpointRounding.AwayFromZero)得到1.90!对于程序员可能遇到的大多数基本问题,Math.Round方法绝对不一致且无法使用。我必须检查if(int)1.905 * decimalPowerOfTen = Math.Round(number * decimalPowerOfTen,2)因为我不想围绕应该舍入的内容。
#15
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));}