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


75
assert(0.1 + 0.2 != 0.3); // shall be true

是我最喜欢的一种语言使用本机浮点算法的检查。

C ++

#include <cstdio>

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

输出:

1

http://ideone.com/ErBMd

蟒蛇

print(0.1 + 0.2 != 0.3)

输出:

True

http://ideone.com/TuKsd

其他例子

为什么D不正确?据了解,D使用本机浮点数。这是一个错误吗?他们是否使用某些特定的数字表示形式?还有吗 相当混乱。

d

import std.stdio;

void main()
{
   writeln(0.1 + 0.2 != 0.3);
}

输出:

false

http://ideone.com/mX6zF


更新

感谢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
}

输出:

false
true

http://ideone.com/z6ZLk


13
请直接在问题中而不是在外部链接中放置相关的代码示例。既可以确保问题中的完整信息得以保留,又可以使其更易于阅读。
安德斯·亚伯

6
我要反身地单击关闭按钮,直到我注意到您写的==不是!=
dan04 2011年

2
关于您的更新:这不是编译器优化程序的“问题”。这是合法的浮点行为,D文档的“浮点常量折叠”部分中说明了这种情况的发生。
路加福音

1
请查看使用real类型而不是类型时发生的情况doubleideone.com/NAXkM
Jean Hominal 2011年

@Jean Hominal:实型案例很有趣。思考...
Stas

Answers:


47

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


27
等等,为什么编译器会进行十进制浮点计算而运行时会进行二进制浮点计算?
Jean Hominal 2011年

好点子。有趣的是,我只是尝试了一下,但是我变得虚假了。我自己无法复制OP的结果。我正在编译为32位,但我想知道64位是否有所作为。
Flynn1179 2011年

13
这是正确的答案。请参阅d-programming-language.org/float.html的“浮点常量折叠”部分。
路加福音

1
绝对可以进行优化。对变量进行了相同的尝试,并实现了:ideone.com/zO4OD
bezmax 2011年

3
嘿,我只是重新阅读了问题;我以“ D”表示,您的意思是该列表中的第四个示例;我试图用C#对其进行复制!
Flynn1179 2011年

53

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


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

尽管(如Ben所指出的那样),浮点错误确定性的,但从代码的角度来看,如果您不是很仔细地考虑每一步值的变化,情况就不会如此。任何数量的因素都可能导致0.1 + 0.2 == 0.3成功的编译时优化成为其中的一个,而对那些文字进行调整后的值则成为另一个。

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


25
这是一个很好的观点-您不能依靠浮点算法来给您错误的答案!:-)
史蒂夫·摩根

8
只要您使用序列点和变量赋值来强制在每一步进行舍入,浮点数误差就可以产生确定的,可预测的答案。并且,/fp:precise应注意避免使用舍入方法的编译器选项,例如使用MSVC 。
Ben Voigt

7
这是一个可怕的解释。IEEE 754明确定义了基本操作,包括+。这里的问题是编程语言之一,而不是浮点数。同样,浮点数相等也被完美定义。当您不想要它时,就不应该使用它,仅此而已。
Pascal Cuoq

@Pascal:IEEE 754可以。D没有。您断言“这里的问题是一种编程语言”,而且...您是对的!如果你在这个问题看起来真的很仔细,你会看到,它被标记d,没有IEEE 754。我真的希望能帮助您理解这个问题。
在轨道进行比赛

@本:当然,如果您控制所有这些因素。我的回答确实假定程序员没有这样做。我对单词的回答进行了更好的编辑。
Lightness Races in Orbit

5

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

但是,必须检查一下是否足以解释您观察到的结果。


2
哇,@ Tomalak,我的头刚刚爆炸了;-)
史蒂夫·摩根

2
@Tomalak:以及0.2和0.3一样-但以80位精度(而不是64位)舍入可以使值“等于”而不是不同。我刚刚检查了具有实型的变量,并且它再次评估为false:ideone.com/sIFgk
Jean Hominal 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.