[英]Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72
I have a bug with Math.Round with no explanation. 我有一个Math.Round的错误没有解释。 When I make 当我做
Math.Round(81.725, 2, MidpointRounding.AwayFromZero)
The result is 81,72 but when I make the same with Decimal.Round 结果是81,72但是当我用Decimal.Round做同样的时候
Decimal.Round(81.725M, 2, MidpointRounding.AwayFromZero)
The result is 81,73 结果是81,73
I d'ont understand why, have you an solution to use Math.Round systematically ? 我知道为什么,你有一个系统地使用Math.Round的解决方案吗?
You shouldn't be talking about bugs before understanding how double
works, and the differences with decimal
that explain the behavior you are seeing. 在理解double
作用之前,你不应该讨论错误 ,以及解释你所看到的行为的decimal
差异。
A double is the best approximation of a real number with the following structure: double是具有以下结构的实数的最佳近似值:
number = sign * mantissa * 2 ^ exponent
Therefore, the number 81.725,
when represented as a double
, is really: 因此,当表示为double
时,数字81.725,
实际上是:
1 * 2875442808959795 * 2^-45 = 81,724999999999994315658113919199
Now you should understand why Math.Round(81.725, 2)
resolves to 81.72
and not 81.73
. 现在你应该理解为什么Math.Round(81.725, 2)
解析为81.72
而不是81.73
。
This doesn't happen with decimal
because decimal
, contrary to double
, can exactly represent 81.725
. decimal
不会发生这种情况,因为与double
相反, decimal
可以精确地表示为81.725
。 This is due to the fact that the scaling factor in decimal
is a power of 10
. 这是因为decimal
中的缩放因子是10
的幂。
This added precision obviously comes at a cost, in speed, space and range. 这种增加的精度显然是在成本,速度,空间和范围上。 When to choose one type or the other is well explained in a link to another SO question provided in comments. 何时选择一种类型或另一种类型在评论中提供的另一个SO问题的链接中得到很好的解释。
The M
suffix on second assignment below determines data type: 下面第二个分配的M
后缀确定数据类型:
Math.Round(81.725, 2, MidpointRounding.AwayFromZero); // double, returns 81.72
Math.Round(81.725M, 2, MidpointRounding.AwayFromZero); // decimal, returns 81.73
Decimal.Round(81.725M, 2, MidpointRounding.AwayFromZero); // decimal, returns 81.73
By using that suffix, the given data type on second assignment treated as decimal
instead of double
, makes the rounding more precise. 通过使用该后缀,第二个赋值的给定数据类型被视为decimal
而不是double
,使舍入更精确。
The MSDN documentation of Math.Round already mention this difference: Math.Round的MSDN文档已经提到了这个区别:
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)
method may not appear to round midpoint values to the nearest even integer. 由于将十进制值表示为浮点数或对浮点值执行算术运算可能导致精度损失,因此在某些情况下,Round(Double)
方法可能看起来不会将中点值舍入到最接近的偶数整数。
And there is further explanation for Decimal.Round : 还有对Decimal.Round的进一步解释:
The behavior of this method follows IEEE Standard 754, section 4. This kind of rounding is sometimes called round half to even or banker's rounding. 此方法的行为遵循IEEE标准754第4节。这种舍入有时被称为舍入到偶数或银行家的舍入。 It minimizes rounding errors that result from consistently rounding a midpoint value in a single direction. 它最大限度地减少了在单个方向上始终舍入中点值所导致的舍入误差。 It is equivalent to calling the
Round(Decimal, MidpointRounding)
method with a mode argument ofMidpointRounding.ToEven
. 它相当于调用Round(Decimal, MidpointRounding)
用的模式参数的方法MidpointRounding.ToEven
。
In short, decimal
uses IEEE-754 which uses consistent rounding for midpoint value, while double
(and float
) uses floating-point which has no finite binary representation. 简而言之, decimal
使用IEEE-754,它对中点值使用一致的舍入,而double
(和float
)使用没有有限二进制表示的浮点。
Other reference: 其他参考:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.