为什么D + 0.1 + 0.2 == 0.3?

Sta*_*tas 75 floating-point d floating-accuracy constantfolding

assert(0.1 + 0.2 != 0.3); // shall be true
Run Code Online (Sandbox Code Playgroud)

是我最喜欢的检查,语言使用本机浮点运算.

C++

#include <cstdio>

int main()
{
   printf("%d\n", (0.1 + 0.2 != 0.3));
   return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

1
Run Code Online (Sandbox Code Playgroud)

http://ideone.com/ErBMd

蟒蛇

print(0.1 + 0.2 != 0.3)
Run Code Online (Sandbox Code Playgroud)

输出:

True
Run Code Online (Sandbox Code Playgroud)

http://ideone.com/TuKsd

其他例子

为什么D不适用?理解D使用本机浮点数.这是一个错误吗?他们是否使用某些特定的数字代表?别的什么?很混乱.

d

import std.stdio;

void main()
{
   writeln(0.1 + 0.2 != 0.3);
}
Run Code Online (Sandbox Code Playgroud)

输出:

false
Run Code Online (Sandbox Code Playgroud)

http://ideone.com/mX6zF


UPDATE

感谢LukeH.这是在那里描述的浮点常数折叠的效果.

码:

import std.stdio;

void main()
{
   writeln(0.1 + 0.2 != 0.3); // constant folding is done in real precision

   auto a = 0.1;
   auto b = 0.2;
   writeln(a + b != 0.3);     // standard calculation in double precision
}
Run Code Online (Sandbox Code Playgroud)

输出:

false
true
Run Code Online (Sandbox Code Playgroud)

http://ideone.com/z6ZLk

Lig*_*ica 53

(Flynn的回答是正确的答案.这个问题更普遍地解决了这个问题.)


您似乎在假设OP,您的代码中的浮点不准确性是确定性的并且可预测错误(在某种程度上,您的方法与那些不了解浮点的人的方法相反).

虽然(正如Ben所指出的)浮点不准确性确定性的,但从代码的角度来看,如果你不是非常谨慎地考虑每一步中你的价值观发生了什么,情况就不是这样了.任何数量的因素都可能导致0.1 + 0.2 == 0.3成功,编译时优化成为一个,这些文字的调整值是另一个.

无论是成功还是失败,都不在此; 不管怎样都不要依赖浮点相等.

  • 这是一个非常好的观点 - 你不能依赖浮点运算给你错误的答案!:-) (25认同)
  • 浮点不准确性产生确定性的,可预测的答案......只要您使用序列点和变量赋值来强制每一步舍入.并且,要注意将消除舍入的编译器选项,例如使用MSVC`/fp:precise`. (8认同)
  • 这是一个可怕的解释.IEEE 754明确定义了基本操作,包括`+`.这里的问题是编程语言之一,而不是浮点问题.此外,浮点相等是完美定义的.当它不是你想要的时候你就不应该使用它,就是这样. (7认同)

Fly*_*179 47

它可能被优化为(0.3!= 0.3).这显然是假的.检查优化设置,确保它们已关闭,然后重试.

  • 等等,为什么编译器会进行十进制浮点计算而运行时进行二进制浮点计算? (26认同)
  • 这是正确的答案.请参阅http://www.d-programming-language.org/float.html的"浮点常量折叠"部分. (13认同)
  • 嘿,我刚刚重新阅读了这个问题; 我想'D',你的意思是该列表中的第四个例子; 我试图用C#重新编写它! (3认同)
  • 我只是尝试了与真实变量相同并且变为现实.http://ideone.com/sIFgk (2认同)

Jea*_*nal 5

根据我对D语言规范的解释,x86上的浮点运算将在内部使用80位精度,而不是仅使用64位.

然而,人们必须检查这是否足以解释您观察到的结果.

  • 0.1是无限的. (6认同)
  • 哇,@ Tomalak,我的头刚刚爆炸;-) (2认同)
  • @Tomalak:和0.2和0.3一样 - 但是用80位精度而不是64位进行舍入可以使值"相等"而不是明显.我刚刚检查了具有真实类型的变量,并且它再次评估为false:http://ideone.com/sIFgk (2认同)