为什么 Math.Round(2.5) 返回 2 而不是 3?
在 C# 中,Math.Round(2.5)
的结果是 2。
它应该是 3,不是吗? 为什么在 C# 中是 2?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
在 C# 中,Math.Round(2.5)
的结果是 2。
它应该是 3,不是吗? 为什么在 C# 中是 2?
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(15)
首先,这无论如何都不会是 C# 错误 - 它会是 .NET 错误。 C# 是一种语言 - 它不决定如何实现 Math.Round。
其次,不 - 如果您阅读文档,您会看到默认舍入为“四舍五入”(银行舍入):
您可以使用 Math.Round 如何舍入中点>重载,它采用
MidpointRounding
值。 有一个带有MidpointRounding
的重载,对应于每个没有中点舍入的重载:四舍五入(十进制)
/舍入(小数、中点舍入)
圆形(双)
/ <代码>圆形(双精度,中点舍入)舍入(十进制,Int32)
/舍入(十进制、Int32、中点舍入)
舍入(双精度,Int32)
/Round( Double、Int32、MidpointRounding)
这个默认值是否选择得当是另一回事。 (
MidpointRounding
仅在 .NET 2.0 中引入。在此之前,我不确定是否有任何简单的方法可以在不亲自执行的情况下实现所需的行为。)特别是,历史表明它不是预期行为 - 在大多数情况下,这是 API 设计中的一个主要错误。 我明白为什么银行家四舍五入很有用......但它仍然让很多人感到惊讶。您可能有兴趣查看最近的 Java 等效枚举 (
RoundingMode
)提供了更多选项。 (它不仅仅处理中点。)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):
You can specify how
Math.Round
should round mid-points using an overload which takes aMidpointRounding
value. There's one overload with aMidpointRounding
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.)这称为舍入为偶数(或银行家舍入),这是一种有效的舍入策略,可最大限度地减少总和中的累积误差
(MidpointRounding.ToEven)
。 理论上来说,如果您总是向同一方向舍入 0.5 的数字,则错误会更快地累积(舍入到偶数应该可以最大限度地减少错误)(a)。请点击以下链接获取 MSDN 描述:
Math.Floor
,向下舍入到负无穷大。Math.Ceiling
,向上舍入为正无穷大。Math.Truncate
,向上或向下舍入为零。Math.Round
,四舍五入到最接近的整数或指定的小数位数。 如果两种可能性之间的距离完全相等,您可以指定行为,例如四舍五入以使最终数字为偶数(“Round(2.5,MidpointRounding.ToEven)
”变为 2)或使其距离更远从零(“Round(2.5,MidpointRounding.AwayFromZero)
”变为 3)。下面的图表可能会有所帮助:
请注意,
Round
比看起来强大得多,因为它可以四舍五入到特定的小数位数。 所有其他的始终四舍五入到零小数。 例如:对于其他函数,您必须使用乘法/除法技巧来达到相同的效果:
(a) 当然,该理论取决于这样的事实:您的数据具有相当均匀的分布偶数部分(0.5、2.5、4.5,...)和奇数部分(1.5、3.5,...)的值。
例如,如果所有“半值”都是偶数,则错误的累积速度将与始终向上舍入一样快。
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:
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:With the other functions, you have to use multiply/divide trickery to achieve the same effect:
(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.
您应该检查 MSDN 中的
Math.Round
:您可以使用重载指定
Math.Round
的行为:You should check MSDN for
Math.Round
:You can specify the behavior of
Math.Round
using an overload:从 MSDN,Math.Round(double a) 返回:
...因此 2.5 位于 2 和 3 之间,向下舍入为偶数 (2)。 这称为银行家舍入(或舍入到偶数),并且是常用的舍入标准。
同一篇 MSDN 文章:
您可以通过调用采用
MidpointRounding
模式的 Math.Round 重载来指定不同的舍入行为。From MSDN, Math.Round(double a) returns:
... 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:
You can specify a different rounding behavior by calling the overloads of Math.Round that take a
MidpointRounding
mode.四舍五入的本质
考虑将包含分数的数字四舍五入为整数的任务。 在这种情况下,四舍五入的过程是确定哪个整数最能代表要四舍五入的数字。
在常见的或“算术”舍入中,很明显 2.1、2.2、2.3 和 2.4 舍入为 2.0; 以及2.6、2.7、2.8和2.9至3.0。
剩下的就是 2.5,它与 2.0 的距离并不比与 3.0 的距离更近。 您可以在 2.0 和 3.0 之间进行选择,任一者都同样有效。
对于负数,-2.1、-2.2、-2.3 和 -2.4 将变为 -2.0; -2.6、2.7、2.8 和 2.9 在算术舍入下将变为 -3.0。
对于 -2.5,需要在 -2.0 和 -3.0 之间进行选择。
其他形式的四舍五入
“四舍五入”取任何带小数位的数字,并将其作为下一个“整数”数字。 因此,不仅 2.5 和 2.6 舍入为 3.0,2.1 和 2.2 也舍入为 3.0。
向上舍入会使正数和负数远离零。 例如。 2.5至3.0和-2.5至-3.0。
“向下舍入”通过去掉不需要的数字来截断数字。 这具有将数字移向零的效果。 例如。 2.5 至 2.0 和 -2.5 至 -2.0
在“银行四舍五入”(最常见的形式)中,要四舍五入的 0.5 向上或向下四舍五入,以便四舍五入的结果始终为偶数。 因此,2.5 轮到 2.0、3.5 轮到 4.0、4.5 轮到 4.0、5.5 轮到 6.0,依此类推。
“交替舍入”可在向下舍入和向上舍入之间交替处理任何 0.5。
“随机舍入”完全随机向上或向下舍入 0.5。
对称和不对称
如果舍入函数将所有数字远离零舍入或将所有数字舍入到零,则该舍入函数被称为“对称”。
如果将正数四舍五入到零,将负数四舍五入远离零,则函数是“不对称”的。 2.5至2.0; 和-2.5至-3.0。
同样不对称的函数是将正数从零舍入,将负数舍入到零。 例如。 2.5至3.0; 和-2.5至-2.0。
大多数时候人们会想到对称舍入,其中 -2.5 将向 -3.0 舍入,3.5 将向 4.0 舍入。(在 C# 中
Round(AwayFromZero) )
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)
)默认的
MidpointRounding.ToEven
或银行家舍入(2.5 变为 2、4.5 变为 4 等等)之前在编写会计报告时曾让我感到困扰,所以我将写下我之前和这篇文章的研究中发现的一些内容。这些四舍五入为偶数的银行家是谁(也许是英国银行家!)?
来自维基百科
这似乎是一种非常奇怪的四舍五入方式,特别是对于银行业来说,当然,除非银行习惯于接收大量金额相同的存款。 存入 240 万英镑,但我们称之为 200 万英镑,先生。
IEEE 标准 754 可以追溯到 1985 年,并提供了两种舍入方式,但标准建议使用银行家舍入方式。 这篇 wikipedia 文章有一长串关于语言如何实现舍入的列表(如果以下任何一项是正确的,请纠正我)错误)并且大多数人不使用银行家的舍入,而是使用您在学校教授的舍入:
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
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:
来自 MSDN:
http://msdn.microsoft。 com/en-us/library/system.math.round.aspx
From MSDN:
http://msdn.microsoft.com/en-us/library/system.math.round.aspx
由于 Silverlight 不支持 MidpointRounding 选项,因此您必须编写自己的选项。 例如:
有关如何使用它作为扩展的示例,请参阅帖子:.NET 和 Silverlight 舍入
Since Silverlight doesn't support the MidpointRounding option you have to write your own. Something like:
For the examples including how to use this as an extension see the post: .NET and Silverlight Rounding
我遇到了这样的问题:我的 SQL 服务器将 0.5 舍入为 1,而我的 C# 应用程序却没有。 所以你会看到两个不同的结果。
这是 int/long 的实现。 Java 就是这样循环的。
这可能也是您能想到的最有效的方法。
如果您想将其保留为 double 并使用小数精度,那么实际上只需根据小数位数使用 10 的指数即可。
小数点可以输入负小数,也没有问题。
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.
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.
You can input a negative decimal for decimal points and it's word fine as well.
Silverlight 不支持 MidpointRounding 选项。
下面是 Silverlight 的一个扩展方法,它添加了 MidpointRounding 枚举:
来源:http: //anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/
Silverlight doesn't support the MidpointRounding option.
Here's an extension method for Silverlight that adds the MidpointRounding enum:
Source: http://anderly.com/2009/08/08/silverlight-midpoint-rounding-solution/
简单的方法是:
Simple way is:
使用 .NET 舍入数字 可以提供您正在寻找的答案。
基本上是这样的:
返回值
精度等于数字的最接近值的数字。 如果值是两个数字之间的中间值,其中一个是偶数,另一个是奇数,则返回偶数。 如果值的精度小于数字,则返回值不变。
此方法的行为遵循 IEEE 标准 754 第 4 节。这种舍入有时称为舍入到最接近的舍入或银行家舍入。 如果数字为零,这种舍入有时称为向零舍入。
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
这是我必须解决的方法:
尝试使用 2 位小数的 1.905 将得到预期的 1.91,但 Math.Round(1.905,2,MidpointRounding.AwayFromZero) 给出 1.90! 对于程序员可能遇到的大多数基础问题,Math.Round 方法绝对不一致且无法使用。 我必须检查是否
(int) 1.905 * DecimalPowerOfTen = Math.Round(number * DecimalPowerOfTen, 2)
因为我不想对应该向下舍入的内容进行四舍五入。Here's the way i had to work it around :
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.