提问人:Stas 提问时间:7/29/2011 最后编辑:StayOnTargetStas 更新时间:8/21/2018 访问量:18652
为什么 0.1 + 0.2 == 0.3 in D?
Why 0.1 + 0.2 == 0.3 in D?
问:
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
蟒
print(0.1 + 0.2 != 0.3)
输出:
True
其他例子
为什么 D 不是这样?据了解,D 使用原生浮点数。这是一个错误吗?他们是否使用一些特定的数字表示形式?别的?相当令人困惑。
D
import std.stdio;
void main()
{
writeln(0.1 + 0.2 != 0.3);
}
输出:
false
更新
法典:
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
答:
47赞
Flynn1179
7/29/2011
#1
它可能被优化为 (0.3 != 0.3)。这显然是错误的。检查优化设置,确保它们已关闭,然后重试。
评论
27赞
Jean Hominal
7/29/2011
等等,为什么编译器要做十进制浮点计算,运行时要做二进制浮点计算?
0赞
Flynn1179
7/29/2011
好点子。有趣的是,我刚刚尝试过这个,我得到了假的;我自己无法重现 OP 的结果。我正在编译为 32 位,我想知道 64 位是否有区别。
13赞
LukeH
7/29/2011
这是正确答案。请参阅 d-programming-language.org/float.html 的“浮点常量折叠”部分。
1赞
bezmax
7/29/2011
绝对是优化的东西。对变量进行了相同的尝试并得到了真实:ideone.com/zO4OD
3赞
Flynn1179
7/29/2011
呵呵,我只是重读了这个问题;我以为“D”是指该列表中的第四个示例;我试图在 C# 中重现它!
5赞
Jean Hominal
7/29/2011
#2
根据我对 D 语言规范的解释,x86 上的浮点运算将在内部使用 80 位精度,而不仅仅是 64 位。
然而,人们必须检查这是否足以解释你观察到的结果。
评论
2赞
Steve Morgan
7/29/2011
哇,@Tomalak,我的脑袋刚刚爆炸了;-)
2赞
Jean Hominal
7/29/2011
@Tomalak:0.2 和 0.3 也是如此 - 但以 80 位精度而不是 64 位四舍五入可能会使值“相等”而不是不同。我刚刚检查了具有真实类型的变量,它再次计算为 false:ideone.com/sIFgk
53赞
Lightness Races in Orbit
7/29/2011
#3
(弗林的答案是正确的答案。这个更普遍地解决了这个问题。
OP 你似乎在假设你的代码中的浮点不准确是确定性的,并且是可预测的错误(在某种程度上,你的方法与那些还不了解浮点的人截然相反)。
尽管(正如 Ben 所指出的)浮点不准确性是确定性的,但从代码的角度来看,如果你没有非常慎重地考虑每一步的值发生了什么,情况就不是这样了。任何数量的因素都可能导致成功,编译时优化是其中之一,调整这些文字的值是另一回事。0.1 + 0.2 == 0.3
在这里既不依赖成功,也不依赖失败;无论哪种方式,都不要依赖浮点相等。
评论
25赞
Steve Morgan
7/29/2011
这是一个很好的观点——你不能依靠浮点运算给你错误的答案!:-)
8赞
Ben Voigt
7/30/2011
浮点不准确确实会产生确定的、可预测的答案......只要您使用序列点和对变量的赋值来强制在每一步进行舍入。并且,请注意将消除舍入的编译器选项,例如应使用 MSVC。/fp:precise
7赞
Pascal Cuoq
7/31/2011
这是一个可怕的解释。IEEE 754 明确定义了基本操作,包括 .这里的问题是编程语言的问题,而不是浮点问题。此外,浮点相等性也得到了完美的定义。当它不是你想要的时,你不应该使用它,仅此而已。+
0赞
Lightness Races in Orbit
8/1/2011
@Pascal:IEEE 754 确实如此。D 没有。你断言“这里的问题是一门编程语言”,并且......你是对的!如果你仔细观察这个问题,你会发现它被标记为 ,而不是 。我真的希望这能帮助你理解这个问题。d
IEEE 754
0赞
Lightness Races in Orbit
8/1/2011
@Ben:当然,如果你控制了所有这些因素。我的回答确实假设程序员不会这样做。我把我的答案编辑得更好。
评论
==
!=
real
double