Floating point 为什么是0.1+;0.2==0.3英寸D?

Floating point 为什么是0.1+;0.2==0.3英寸D?,floating-point,floating-accuracy,d,constantfolding,Floating Point,Floating Accuracy,D,Constantfolding,是我最喜欢的检查语言是否使用本机浮点运算的方法 C++ python 输出: #include <cstdio> int main() { printf("%d\n", (0.1 + 0.2 != 0.3)); return 0; } print(0.1 + 0.2 != 0.3) import std.stdio; void main() { writeln(0.1 + 0.2 != 0.3); } import std.stdio; void ma

是我最喜欢的检查语言是否使用本机浮点运算的方法

C++

python 输出:

#include <cstdio>

int main()
{
   printf("%d\n", (0.1 + 0.2 != 0.3));
   return 0;
}
print(0.1 + 0.2 != 0.3)
import std.stdio;

void main()
{
   writeln(0.1 + 0.2 != 0.3);
}
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
}

其他例子
  • 爪哇:
  • C#:
为什么对D来说不是这样?正如我们所理解的,D使用本机浮点数。这是虫子吗?他们是否使用特定的数字表示法?还有别的吗?相当混乱

D 输出:

#include <cstdio>

int main()
{
   printf("%d\n", (0.1 + 0.2 != 0.3));
   return 0;
}
print(0.1 + 0.2 != 0.3)
import std.stdio;

void main()
{
   writeln(0.1 + 0.2 != 0.3);
}
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
}


更新 多亏了。这是浮点常量折叠的一种效果

代码:

输出:

#include <cstdio>

int main()
{
   printf("%d\n", (0.1 + 0.2 != 0.3));
   return 0;
}
print(0.1 + 0.2 != 0.3)
import std.stdio;

void main()
{
   writeln(0.1 + 0.2 != 0.3);
}
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
}

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

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

然而,你必须检查这是否足以解释你观察到的结果。

(弗林的答案是正确的。这一答案更全面地解决了这个问题。)


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

尽管(正如Ben所指出的)浮点不准确是确定的,但从代码的角度来看,如果您没有仔细考虑每一步的值发生了什么,情况就不会是这样了。任何数量的因素都可能导致
0.1+0.2==0.3
成功,编译时优化是一个因素,那些文本的调整值是另一个因素



在这里,既不依赖成功,也不依赖失败;无论哪种方式,都不要依赖浮点等式。

请直接在问题中输入相关代码示例,而不要在外部链接中输入。为了确保问题中的完整信息保留下来并使其更易于阅读,我本打算本能地单击关闭按钮,直到我注意到您编写了
==
而不是
=。关于您的更新:这不是编译器优化程序的“问题”。这是合法的浮点行为,发生这种情况的可能性在D文档的后面部分进行了解释。请查看使用
real
类型而不是
double
type:@Jean homial:real类型的情况很有趣。思考…等等,为什么编译器要进行十进制浮点计算,而运行时要进行二进制浮点计算?好的。有趣的是,我刚刚试过这个,但我得到的是错误的;我自己也不能重述OP的结果。不过我正在编译为32位,我想知道64位是否会有所不同。这是正确的答案。请参阅的“浮点常量折叠”一节。明确地说,它与优化有关。对变量也做了同样的尝试,结果是:嘿,我只是重新阅读了这个问题;我认为“D”是指列表中的第四个例子;我正试着用C#重新编程呢!这是一个非常好的点-你不能依靠浮点运算给出错误的答案浮点不精确确实会产生确定性的、可预测的答案。。。只要使用序列点和变量赋值在每一步强制舍入。另外,要注意那些会消除舍入的编译器选项,例如使用MSVC
/fp:precise
,这是一个糟糕的解释。IEEE 754明确定义了基本操作,包括
+
。这里的问题是编程语言,而不是浮点。此外,浮点等式的定义是完美的。当它不是你想要的东西时,你不应该使用它,仅此而已。@Pascal:IEEE 754就是这样做的。D没有。您断言“这里的问题是一种编程语言”,并且。。。你说得对!如果你仔细观察这个问题,你会发现它被标记为
d
,而不是
ieee754
。我真的希望这能帮助你理解这个问题。@Ben:当然,如果你能控制所有这些因素的话。我的回答是假定程序员不会这样做。我把我的答案编辑得更好。哇,托马拉克,我的脑袋爆炸了;-)@托马拉克:0.2和0.3也是一样,但是用80位精度而不是64位精度的舍入可以使值“相等”而不是“不同”。我刚刚检查了实数类型的变量,它的计算结果再次为false: