Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72

时间:2017-04-05 08:41:56

标签: c# math

我有一个Math.Round的错误,没有任何解释。 我做的时候

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

结果是81,72,但是当我使用Decimal.Round

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

结果是81,73

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

2 个答案:

答案 0 :(得分:3)

在了解Json -> {"abc":"123","def":"456","ghi":"789"} 的工作原理之前,您不应该讨论错误,以及与double的区别,这些差异可以解释您所看到的行为。

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

decimal

因此,number = sign * mantissa * 2 ^ exponent 表示为81.725,,实际上是:

double

现在你应该理解为什么1 * 2875442808959795 * 2^-45 = 81,724999999999994315658113919199 解析为Math.Round(81.725, 2)而不是81.72

81.73不会发生这种情况,因为与decimal相反,decimal可以完全代表double。这是因为81.725中的缩放因子是decimal的幂。

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

答案 1 :(得分:0)

下面第二项作业的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,使得舍入更精确。

MSDN documentation of Math.Round已经提到了这种差异:

  

来电者注意事项:

     

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

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

  

此方法的行为遵循IEEE标准754第4节   圆形有时被称为圆形<强>一半到均匀或银行家   舍入。它最大限度地减少了始终如一的舍入误差   在单个方向上舍入中点值。它相当于   使用模式调用Round(Decimal, MidpointRounding)方法   MidpointRounding.ToEven的论据。

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

其他参考:

Declaration suffix for decimal type