C# 为什么 System.MidpointRounding.AwayFromZero 在这种情况下不四舍五入?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9221205/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why does System.MidpointRounding.AwayFromZero not round up in this instance?
提问by John W
In .NET, why does System.Math.Round(1.035, 2, MidpointRounding.AwayFromZero)yield 1.03 instead of 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.
在 .NET 中,为什么System.Math.Round(1.035, 2, MidpointRounding.AwayFromZero)yield 1.03 而不是 1.04?我觉得我的问题的答案在于http://msdn.microsoft.com/en-us/library/ef48waz8.aspx 上标有“呼叫者注意事项”的部分,但我无法理解解释。
采纳答案by Chris Shain
Your suspicion is exactly right. Numbers with fractional portion, when expressed as literals in .NET, are by default doubles. 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). In this case, the approximation is ever so vanishingly on the small side of 1.035. If you write it using an explicit Decimal it works as you expect:
你的怀疑完全正确。带有小数部分的数字在 .NET 中表示为文字时,默认为doubles。双精度(如浮点数)是十进制值的近似值,而不是精确的十进制值。它是可以用 base-2(二进制)表示的最接近的值。在这种情况下,近似值在 1.035 的小边上几乎消失得无影无踪。如果您使用显式 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). You can't- it translates to .3333333...., meaning that to represent it accurately would require an infinite amount of memory.
要理解为什么双精度和浮点数以它们的方式工作,想象一下用十进制(或二进制,它遇到同样的问题)来表示数字 1/3。你不能 - 它转换为 .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
回答by Craig Shearer
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.
不过只是猜测。
回答by DRobinson
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. 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. 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.
我相信你所指的例子是一个不同的问题;据我所知,他们说 0.1 没有存储在浮点数中,就像 0.1 一样,由于浮点数以二进制形式存储,它实际上略有偏差。因此,让我们假设它实际上看起来更像 0.0999999999999(或类似值),非常非常略小于 0.1 - 如此之小以至于不会产生太大差异。好吧,不,他们是说:一个明显的区别是,将它添加到您的数字和四舍五入实际上似乎是错误的,因为即使数字非常接近,它仍然被认为“小于”四舍五入的 0.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.
不过,我看不出它与您的电话有何关系,因为您说得更明确了。也许它只是以类似的方式存储您的号码。
回答by Maxim
I'ts because the BINARY representation of 1.035 closer to 1.03 than 1.04
因为 1.035 的 BINARY 表示比 1.04 更接近 1.03
For better results do it this way -
为了更好的结果这样做 -
decimal result = decimal.Round(1.035m, 2, MidpointRounding.AwayFromZero);
回答by Jeffrey Wang
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, MidpointZounding) 是 0x3FF08F5C28F5C28F,所以 4.From1Rounding 是
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'). 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.
然而,4.005d 的二进制表示是 0x4010051EB851EB85,也就是 4.00499999999999989341858963598,所以 System.Math.Round(4.005, 2, MidpointRounding should.Away butFrom4ero) 是错误的。如果你在 MS SQL select 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

