当倍增双倍时,我遇到了相当奇怪的行为。
创建一个简单的控制台应用程序并尝试使用代码。
private static void Main(string[] args)
{
var b1 = 3.1 * 100D;
var a1 = 4.1 * 100D;
// put breakpoint here and observe b1 and a1 values, to me they are
// b1=310, a1=409.99999999999994
Console.WriteLine(a1);
// notice that Console.WriteLine actually returns 410
}
我怀疑这是二进制中的双重表示,但我无法解释自己是如何可能的,你能帮助我吗?
此外,如果您将a1
投射到decimal
,它会以某种方式变为410 ......
我尝试编译C#3.0和C#7.0都给出了相同的结果。我在Visual Studio 2017中重现了这一点。
答案 0 :(得分:2)
(回答“为什么310 == 3.1 * 100”部分)
这只是“偶然”3.1 * 100 == 310
。
碰巧浮点算术运算的特殊方式,
3.1 * 100的结果给出了310.0000...
。如果将310转换为double,则此数字与您获得的结果完全匹配。
在这种特殊情况下,
会很愉快地进行比较。您可以使用DoubleConverter.ToExactString() function from Jon Skeet
查看它 Console.WriteLine(DoubleConverter.ToExactString(3.1 * 100));
Console.WriteLine(DoubleConverter.ToExactString(4.1 * 100));
// output :
// 310
// 409.99999999999994315658113919198513031005859375
在这种特殊情况下,表达式4.1 * 100D
是double
乘以double
。
4.1 * 100
(double
次int
- > int
隐式转换为double
)会导致同样的错误
由于没有为变量指定类型,编译器选择将结果解释为double
。在这种特殊情况下,由浮点运算引起的舍入误差(4.1没有精确表示为double
)
如果变量定义为decimal
,则结果为decimal
,并且不会发生舍入错误。请注意,您不能只在您提供的代码中将var
更改为decimal
,还必须更改变量:
在这种情况下,乘法将在两种情况下都给出精确的十进制值。
有关此处的浮点错误的更多信息:Is floating point math broken?
decimal a1 = 4.1 * 100D; // compilation error : no implicit cast from double to decimal
decimal a1 = 4.1M * 100; // valid, and the multiplication will be performed exactly.