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

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


更新

这是一个描述为 abc1的浮点常数折叠的效果。

密码:

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

18501 次浏览

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

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

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

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


OP,您似乎假设代码中的浮点数不准确性是确定性的,而且是 意料之中的错误(在某种程度上,您的方法与那些还不理解浮点数的人的方法截然相反)。

虽然(正如 Ben 指出的)浮点不精确 是确定性的,但从代码的角度来看,如果你没有非常仔细地考虑在每一步都发生了什么,那么情况就不会是这样。任何数量的因素都可能导致 0.1 + 0.2 == 0.3的成功,编译时优化是其中之一,这些字面值的调整值是另一个。

这里依赖于 都不是的成功或失败,不依赖于浮点等式 不管怎样