为什么在 .NET 中将两个双精度相乘时会发生这种情况 [duplicate]

Why this happens when multiplying two doubles in .NET [duplicate]

提问人:kuskmen 提问时间:12/19/2017 最后编辑:Pac0kuskmen 更新时间:12/19/2017 访问量:214

问:

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

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

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
}

我怀疑这是二进制的双重表示,但我无法解释自己这是怎么回事,你能帮我吗?

另外,如果你投射到它以某种方式变成 410......a1decimal

我尝试针对 C# 3.0 和 C#7.0 进行编译,结果相同。我在Visual Studio 2017中重现了这一点。

C# .NET 点浮 点精度

评论

1赞 DodgyCodeException 12/19/2017
你是在问为什么 4.1*100 不完全是 410,或者为什么 3.1*100 是 310 而不是 309.9999999999999994?
1赞 DodgyCodeException 12/19/2017
@NightOwl888 Microsoft说不建议将往返格式用于双打,您应该改用 G17。
1赞 kuskmen 12/19/2017
@i486 谁说我在使用 var 或这种行为时有问题,或者无法解决我的计算问题?我问了非常具体的问题,你根本没有回答,请坚持这个问题,或者不要向线程发送垃圾邮件,谢谢。
2赞 Pac0 12/19/2017
我取消了删除我的答案,以回答为什么 3.1 * 100 似乎有效的细节。这只是偶然的。
2赞 DodgyCodeException 12/19/2017
这取决于你所说的“问题”是什么意思。OP 似乎没有问题,只有一个问题。我的看法是,只要你明白许多小数不能用二进制表示,那么就没有问题。

答:

2赞 Pac0 12/19/2017 #1

编辑

(回答“为什么310==3.1*100”部分)

这只是“偶然”的.3.1 * 100 == 310

只是碰巧浮点运算工作的特定方式, 3.1 * 100 的结果给出 。这个数字与将 310 转换为双精度时得到的结果完全匹配。310.0000...

在这种特殊情况下,比较会很高兴地起作用。

您可以使用 Jon Skeet 的 DoubleConverter.ToExactString() 函数查看它

    Console.WriteLine(DoubleConverter.ToExactString(3.1 * 100));
    Console.WriteLine(DoubleConverter.ToExactString(4.1 * 100));

    // output : 
    // 310
    // 409.99999999999994315658113919198513031005859375

(上一页)

在这种特殊情况下,表达式是 a 乘以 .4.1 * 100Ddoubledouble

同样的错误是由 ( times -> 隐式转换为4.1 * 100doubleintintdouble)

由于没有为变量指定类型,因此编译器选择将结果解释为 .在这种特殊情况下,由于浮点运算会出现舍入误差(4.1 没有精确的表示形式doubledouble)

如果将变量定义为 ,则结果为 ,并且不会发生舍入错误。请注意,您不能只在提供的代码中更改 to,您还必须更改变量:decimaldecimalvardecimal

在这种情况下,乘法将在这两种情况下将给出十进制的确切值。

有关浮点错误的更多信息,请在此处:浮点数学是否损坏?

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.

评论

3赞 DarkSquirrel42 12/19/2017
d 或 D 表示双字面量...
0赞 Pac0 12/19/2017
@DarkSquirrel42是的,我每次都会感到困惑......固定。
4赞 DarkSquirrel42 12/19/2017
是的。。。十进制的 m 并不完全直观......但是想想 MOney
0赞 Pac0 12/19/2017
不错的助记符!
1赞 DodgyCodeException 12/19/2017
是的,但为什么呢?3.1 * 100 == 310