为什么当我执行以下操作时。。。
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^100+2不能完全表示)。
编辑以添加:
在C#中为输出格式化doubles可能有助于理解为什么很难理解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)方法可能不会像模式参数指定的那样对中点值进行舍入。下面的例子说明了这一点,其中2.135四舍五入为2.13,而不是2.14。这是因为该方法内部将值乘以10位数字,并且在这种情况下的乘法运算会损失精度。