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

时间:2012-02-10 00:45:23

标签: c# .net

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

5 个答案:

答案 0 :(得分:30)

你的怀疑是完全正确的。具有小数部分的数字(在.NET中表示为文字时)默认为doubles。双精度(如浮点数)是十进制值的近似值,而不是精确的十进制值。它是可以用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 :(得分:8)

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

答案 2 :(得分:6)

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

为了获得更好的效果,请这样做 -

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

答案 3 :(得分:3)

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

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

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

答案 4 :(得分:1)

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

只是一个猜测。