繁体   English   中英

Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72

[英]Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72

我有一个Math.Round的错误没有解释。 当我做

Math.Round(81.725, 2, MidpointRounding.AwayFromZero)

结果是81,72但是当我用Decimal.Round做同样的时候

Decimal.Round(81.725M, 2, MidpointRounding.AwayFromZero)

结果是81,73

我知道为什么,你有一个系统地使用Math.Round的解决方案吗?

在理解double作用之前,你不应该讨论错误 ,以及解释你所看到的行为的decimal差异。

double是具有以下结构的实数的最佳近似值:

number = sign * mantissa * 2 ^ exponent

因此,当表示为double时,数字81.725,实际上是:

1 * 2875442808959795 * 2^-45 = 81,724999999999994315658113919199

现在你应该理解为什么Math.Round(81.725, 2)解析为81.72而不是81.73

decimal不会发生这种情况,因为与double相反, decimal可以精确地表示为81.725 这是因为decimal中的缩放因子是10的幂。

这种增加的精度显然是在成本,速度,空间和范围上。 何时选择一种类型或另一种类型在评论中提供的另一个SO问题的链接中得到很好的解释。

下面第二个分配的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

通过使用该后缀,第二个赋值的给定数据类型被视为decimal而不是double ,使舍入更精确。

Math.RoundMSDN文档已经提到了这个区别:

来电者须知:

由于将十进制值表示为浮点数或对浮点值执行算术运算可能导致精度损失,因此在某些情况下, Round(Double)方法可能看起来不会将中点值舍入到最接近的偶数整数。

还有对Decimal.Round的进一步解释:

此方法的行为遵循IEEE标准754第4节。这种舍入有时被称为舍入到偶数或银行家的舍入。 它最大限度地减少了在单个方向上始终舍入中点值所导致的舍入误差。 它相当于调用Round(Decimal, MidpointRounding)用的模式参数的方法MidpointRounding.ToEven

简而言之, decimal使用IEEE-754,它对中点值使用一致的舍入,而double (和float )使用没有有限二进制表示的浮点。

其他参考:

十进制类型的声明后缀

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM