【问题标题】:Why this happens when multiplying two doubles in .NET [duplicate]为什么在.NET中将两个双精度相乘时会发生这种情况[重复]
【发布时间】:2018-06-01 21:54:31
【问题描述】:

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

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

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 中重现此内容。

【问题讨论】:

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

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


【解决方案1】:

编辑

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

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

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

比较将很高兴在这种特殊情况下

您可以通过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 * 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.

【讨论】:

  • d 或 D 表示双重文字...
  • @DarkSquirrel42 是的,我每次都感到困惑......已修复。
  • 是的......十进制的 m 并不完全直观......但想想 money
  • 很好的助记符!
  • 是的,但为什么3.1 * 100 == 310
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 2018-12-19
  • 2021-01-24
  • 1970-01-01
  • 1970-01-01
  • 2013-06-09
相关资源
最近更新 更多