简体   繁体   English

Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72

[英]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.RoundMSDN文档已经提到了这个区别:

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 of MidpointRounding.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: 其他参考:

Declaration suffix for decimal type 十进制类型的声明后缀

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

相关问题 JavaScript中的Math.round MidPointRounding.AwayFromZero - Math.round MidPointRounding.AwayFromZero in javascript 使用Math.Round和MidpointRounding.AwayFromZero四舍五入一个数字 - Round a number using Math.Round with MidpointRounding.AwayFromZero 与Delphi中的MidpointRounding.AwayFromZero相当的Math.Round()是什么? - What is the equivalent of Math.Round() with MidpointRounding.AwayFromZero in Delphi? 如何使用NET Math.Round( <decimal> , <int> ,MidpointRounding.AwayFromZero) - How to round off correctly with NET Math.Round(<decimal>,<int>,MidpointRounding.AwayFromZero) 为什么Math.Round(106.8,2,MidpointRounding.AwayFromZero)返回106.8而不是106.80? - Why does Math.Round(106.8, 2, MidpointRounding.AwayFromZero) return 106.8 and not 106.80? 使用Math.Round(ReportItems!category.Value,MidpointRounding.AwayFromZero)返回不正确的值 - Using Math.Round(ReportItems!category.Value,MidpointRounding.AwayFromZero) returns incorrect value .NET Math.Round(<double>,<int>,MidpointRounding.AwayFromZero)无法正常工作 - .NET Math.Round(<double>,<int>,MidpointRounding.AwayFromZero) not working correctly 中点舍入为零 - MidpointRounding.AwayFromZero Math.Round在AwayFromZero模式下失败 - Math.Round fail on AwayFromZero mode 将MidpointRounding.AwayFromZero设置为默认的舍入方法 - Setting MidpointRounding.AwayFromZero as the default rounding method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM