为什么System.MidpointRounding.AwayFromZero在这个实例中不会向上舍入?

在.NET中,为什么System.Math.Round(1.035, 2, MidpointRounding.AwayFromZero)产生1.03而不是1.04? 我觉得我的问题的答案在于http://msdn.microsoft.com/en-us/library/ef48waz8.aspx上标有“呼叫者注意”的部分,但是我无法绕过说明。

你的怀疑是完全正确的。 具有小数部分的数字,在.NET中表示为文字时,默认为双精度数 。 双精度(如浮点数)是十进制值的近似值,而不是精确的十进制值。 它是可以用base-2(二进制)表示的最接近的值。 在这种情况下,近似值在1.035的小范围内是如此消失。 如果使用显式Decimal编写它,它可以按预期工作:

 Console.WriteLine(Math.Round(1.035m, 2, MidpointRounding.AwayFromZero)); Console.ReadKey(); 

要理解为什么双精度浮点数和浮点数按照它们的方式工作,想象一下用十进制数字表示1/3(或二进制数,它会遇到同样的问题)。 你不能 – 它转换为.3333333 ….,意味着要准确地表示它需要无限量的内存。

计算机使用近似值来解决这个问题。 我会详细解释如何,但我可能会弄错。 你可以在这里阅读所有相关内容: http : //en.wikipedia.org/wiki/IEEE_754-1985

1.035d的二进制表示是0x3FF08F5C28F5C28F,实际上是1.03499999999999992006394222699E0,因此System.Math.Round(1.035,2,MidpointRounding.AwayFromZero)产生1.03而不是1.04,所以它是正确的。

但是,4.005d的二进制表示为0x4010051EB851EB85,即4.00499999999999989341858963598,因此System.Math.Round(4.005,2,MidpointRounding.AwayFromZero)应该产生4.00,但它产生4.01这是错误的(或智能’修复’)。 如果你在MS SQL中检查它选择ROUND(CAST(4.005 AS float),2),它是4.00我不明白为什么.NET应用这个“智能修复”会让事情变得更糟。

您可以在http://www.binaryconvert.com/convert_double.html上查看双精度的二进制表示

我是因为1.035的BINARY表示接近1.03而不是1.04

为了更好的结果,这样做 –

 decimal result = decimal.Round(1.035m, 2, MidpointRounding.AwayFromZero); 

我相信你所指的例子是一个不同的问题; 据我所知,他们说0.1没有存储,在浮点数,正好是0.1,它实际上略微偏离,因为浮点数存储在二进制中。 因此,我们假设它实际上看起来更像是0.0999999999999(或类似的),非常非常小于0.1的东西 – 稍微有点不会产生太大的影响。 嗯,不,他们说:一个明显的区别是,将这个添加到你的数字和舍入实际上似乎是错误的方式,因为即使数字非常接近它仍然被认为“小于”.5用于舍入。

如果我误解了那个页面,我希望有人纠正我:)

但是,我不知道它与你的电话有什么关系,因为你更明确。 也许它只是以类似的方式存储您的号码。

在猜测我会说内部1.035不能用二进制表示为1.035而且它可能(在引擎盖下)1.0349999999999999,这就是为什么它向下舍入。

只是一个猜测。