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

Joh*_*n W 33 .net c#

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

Chr*_*ain 31

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

Console.WriteLine(Math.Round(1.035m, 2, MidpointRounding.AwayFromZero));
Console.ReadKey();
Run Code Online (Sandbox Code Playgroud)

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

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


小智 9

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上查看双精度的二进制表示


Max*_*xim 8

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

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

decimal result = decimal.Round(1.035m, 2, MidpointRounding.AwayFromZero);
Run Code Online (Sandbox Code Playgroud)