简体   繁体   English

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

[英]Why does System.MidpointRounding.AwayFromZero not round up in this instance?

In .NET, why does System.Math.Round(1.035, 2, MidpointRounding.AwayFromZero) yield 1.03 instead of 1.04? 在.NET中,为什么System.Math.Round(1.035, 2, MidpointRounding.AwayFromZero)产生1.03而不是1.04? I feel like the answer to my question lies in the section labeled "Note to Callers" at http://msdn.microsoft.com/en-us/library/ef48waz8.aspx , but I'm unable to wrap my head around the explanation. 我觉得我的问题的答案在于http://msdn.microsoft.com/en-us/library/ef48waz8.aspx上标有“呼叫者注意”的部分,但是我无法绕过说明。

Your suspicion is exactly right. 你的怀疑是完全正确的。 Numbers with fractional portion, when expressed as literals in .NET, are by default doubles . 具有小数部分的数字(在.NET中表示为文字时)默认为双精度数 A double (like a float) is an approximation of a decimal value, not a precise decimal value. 双精度(如浮点数)是十进制值的近似值,而不是精确的十进制值。 It is the closest value that can be expressed in base-2 (binary). 它是可以用base-2(二进制)表示的最接近的值。 In this case, the approximation is ever so vanishingly on the small side of 1.035. 在这种情况下,近似值在1.035的小范围内如此消失。 If you write it using an explicit Decimal it works as you expect: 如果使用显式Decimal编写它,它可以按预期工作:

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

To understand why doubles and floats work the way they do, imagine representing the number 1/3 in decimal (or binary, which suffers from the same problem). 要理解为什么双精度浮点数和浮点数按照它们的方式工作,想象一下用十进制数表示1/3(或二进制数,它会遇到同样的问题)。 You can't- it translates to .3333333...., meaning that to represent it accurately would require an infinite amount of memory. 你不能 - 它转换为.3333333 ....,意味着准确地表示它将需要无限的内存。

Computers get around this using approximations. 计算机使用近似值来解决这个问题。 I'd explain precisely how, but I'd probably get it wrong. 我会详细解释如何,但我可能会弄错。 You can read all about it here though: http://en.wikipedia.org/wiki/IEEE_754-1985 你可以在这里阅读所有相关内容: http//en.wikipedia.org/wiki/IEEE_754-1985

The binary representation of 1.035d is 0x3FF08F5C28F5C28F, which in fact is 1.03499999999999992006394222699E0, so System.Math.Round(1.035, 2, MidpointRounding.AwayFromZero) yield 1.03 instead of 1.04, so it's correct. 1.035d的二进制表示是0x3FF08F5C28F5C28F,实际上是1.03499999999999992006394222699E0,因此System.Math.Round(1.035,2,MidpointRounding.AwayFromZero)产生1.03而不是1.04,所以它是正确的。

However, the binary representation of 4.005d is 0x4010051EB851EB85, which is 4.00499999999999989341858963598, so System.Math.Round(4.005, 2, MidpointRounding.AwayFromZero) should yield 4.00, but it yield 4.01 which is wrong (or a smart 'fix'). 但是,4.005d的二进制表示为0x4010051EB851EB85,即4.00499999999999989341858963598,因此System.Math.Round(4.005,2,MidpointRounding.AwayFromZero)应该产生4.00,但它产生4.01这是错误的(或智能'修复')。 If you check it in MS SQL select ROUND(CAST(4.005 AS float), 2), it's 4.00 I don't understand why .NET apply this 'smart fix' which makes things worse. 如果你在MS SQL中检查它选择ROUND(CAST(4.005 AS float),2),它是4.00我不明白为什么.NET应用这个“智能修复”会让事情变得更糟。

You can check binary representation of a double at: http://www.binaryconvert.com/convert_double.html 您可以在http://www.binaryconvert.com/convert_double.html上查看双精度的二进制表示

I'ts because the BINARY representation of 1.035 closer to 1.03 than 1.04 我是因为1.035的BINARY表示接近1.03而不是1.04

For better results do it this way - 为了更好的结果,这样做 -

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

I believe the example you're referring to is a different issue; 我相信你所指的例子是一个不同的问题; as far as I understand they're saying that 0.1 isn't stored, in float, as exactly 0.1, it's actually slightly off because of how floats are stored in binary. 据我所知,他们说0.1没有存储,浮动,正好是0.1,它实际上略微偏离,因为浮点数存储在二进制中。 As such let's suppose it actually looks more like 0.0999999999999 (or similar), something very, very slightly less than 0.1 - so slightly that it doesn't tend to make much difference. 因此,我们假设它实际上看起来更像是0.0999999999999(或类似的),非常非常小于0.1的东西 - 稍微小一些,它不会产生太大的影响。 Well, no, they're saying: one noticeable difference would be that adding this to your number and rounding would actually appear to go the wrong way because even though the numbers are extremely close it's still considered "less than" the .5 for rounding. 嗯,不,他们说:一个明显的区别是,将这个添加到你的数字和舍入实际上似乎是错误的方式,因为即使数字非常接近它仍然被认为“小于”.5用于舍入。

If I misunderstood that page, I hope somebody corrects me :) 如果我误解了那个页面,我希望有人纠正我:)

I don't see how it relates to your call, though, because you're being more explicit. 但是,我不知道它与你的电话有什么关系,因为你更明确。 Perhaps it's just storing your number in a similar fashion. 也许它只是以类似的方式存储您的号码。

At a guess I'd say that internally 1.035 can't be represented in binary as exactly 1.035 and it's probably (under the hood) 1.0349999999999999, which would be why it rounds down. 在猜测我会说内部1.035不能用二进制表示为1.035而且它可能(在引擎盖下)1.0349999999999999,这就是它向下舍入的原因。

Just a guess though. 只是一个猜测。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么Math.Round(106.8,2,MidpointRounding.AwayFromZero)返回106.8而不是106.80? - Why does Math.Round(106.8, 2, MidpointRounding.AwayFromZero) return 106.8 and not 106.80? JavaScript中的Math.round MidPointRounding.AwayFromZero - Math.round MidPointRounding.AwayFromZero in javascript 为什么MidpointRounding.AwayFromZero和MidpointRounding.ToEven做同样的事情? - Why does MidpointRounding.AwayFromZero and MidpointRounding.ToEven do the same thing? 使用Math.Round和MidpointRounding.AwayFromZero四舍五入一个数字 - Round a number using Math.Round with MidpointRounding.AwayFromZero 与Delphi中的MidpointRounding.AwayFromZero相当的Math.Round()是什么? - What is the equivalent of Math.Round() with MidpointRounding.AwayFromZero in Delphi? Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72 - Math.Round bug 81.725 MidpointRounding.AwayFromZero = 81.72 中点舍入为零 - MidpointRounding.AwayFromZero 如何使用NET Math.Round( <decimal> , <int> ,MidpointRounding.AwayFromZero) - How to round off correctly with NET Math.Round(<decimal>,<int>,MidpointRounding.AwayFromZero) 使用Math.Round(ReportItems!category.Value,MidpointRounding.AwayFromZero)返回不正确的值 - Using Math.Round(ReportItems!category.Value,MidpointRounding.AwayFromZero) returns incorrect value .NET Math.Round(<double>,<int>,MidpointRounding.AwayFromZero)无法正常工作 - .NET Math.Round(<double>,<int>,MidpointRounding.AwayFromZero) not working correctly
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM