为什么当我执行以下操作时...
Math.Round(0.75, 1, MidpointRounding.AwayFromZero)
我得到 0.8
但是当我执行以下操作时...
Math.Round(0.575, 2, MidpointRounding.AwayFromZero)
我没有得到 0.58。相反,我得到 0.57。我想要任何 5 及以上的四舍五入,所以 0.575 应该是 0.58。
为什么当我执行以下操作时...
Math.Round(0.75, 1, MidpointRounding.AwayFromZero)
我得到 0.8
但是当我执行以下操作时...
Math.Round(0.575, 2, MidpointRounding.AwayFromZero)
我没有得到 0.58。相反,我得到 0.57。我想要任何 5 及以上的四舍五入,所以 0.575 应该是 0.58。
问题是您不能将 0.575 完全表示为二进制浮点数(例如双精度数)。虽然我并不确切知道,似乎最接近的表示可能只是有点低,所以在四舍五入时它使用真实的表示并向下舍入。
如果您想避免此问题,请使用更合适的数据类型。decimal
会做你想做的事:
Math.Round(0.575M, 2, MidpointRounding.AwayFromZero)
结果:0.58
0.75 正确的原因是它很容易用二进制浮点表示,因为它是简单的 1/2 + 1/4(即 2^-1 +2^-2)。通常,任何 2 的有限幂和都可以用二进制浮点数表示。例外情况是您的 2 的幂跨越的范围太大(例如 2^100+2 不能完全表示)。
编辑添加:
在 C# 中为输出格式化双精度值可能有助于理解为什么很难理解 0.575 并不是真正的 0.575。接受的答案中的 DoubleConverter 将显示 0.575 作为精确字符串0.5749999999999999555910790149937383830547332763671875
您可以从中看出为什么舍入给出 0.57。
该System.Math.Round
方法使用的Double
结构,正如其他人指出的那样,容易出现浮点精度错误。当我遇到这个问题时,我发现的简单解决方案是使用该System.Decimal.Round
方法,它不会遇到同样的问题并且不需要将变量重新定义为小数:
Decimal.Round(0.575, 2, MidpointRounding.AwayFromZero)
结果:0.58
这是由于双精度/小数缺乏精度引起的(即 - 该函数不会总是给出您期望的结果)。
请参阅以下链接:MSDN on Math.Round
这是相关的报价:
由于将十进制值表示为浮点数或对浮点值执行算术运算可能导致精度损失,因此在某些情况下,Round(Double, Int32, MidpointRounding) 方法可能不会按照指定的方式舍入中点值通过 mode 参数。这在以下示例中进行了说明,其中 2.135 舍入为 2.13 而不是 2.14。发生这种情况是因为该方法在内部将值乘以 10 位,并且在这种情况下,乘法运算会损失精度。