为什么在.NET

时间:2017-12-19 12:45:09

标签: c# .net floating-point floating-accuracy

当倍增双倍时,我遇到了相当奇怪的行为。

创建一个简单的控制台应用程序并尝试使用代码。

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中重现了这一点。

1 个答案:

答案 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 * 100Ddouble乘以double

4.1 * 100doubleint - > 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.