Python C++浮点数学表示错误

Don*_*wik 2 c++ python floating-point

在C++中,

double x = 1.0; 
double y = x / 3.0; 
if (x == y * 3.0)
  cout << " They are equal!" ; 
else
  cout << " They are NOT equal." ;
Run Code Online (Sandbox Code Playgroud)

将打印

‘They are NOT equal.’ 
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,由于1/3的非精确表示为(二进制)数量的有限大小的尾数.但是在Python中(在https://repl.it/repls/MessyJaggedMouse上),

x = 1.0
y = x / 3.0
x == y * 3.0
Run Code Online (Sandbox Code Playgroud)

版画

True
Run Code Online (Sandbox Code Playgroud)

何时以及为什么Python会偏离上述预期的行为?编辑:Python不会离开 - 请参阅下面的答案.

Die*_*Epp 6

只有当我在C中使用x87数学时才会发生这种情况.

正确舍入,使用IEEE 754双算术,你将得到真实.

但是,如果以更高的精度计算中间值,则可能会出错.C不需要以64位精度计算所有中间值,而在具有x87浮点指令的32位x86处理器上,最终将使用较大的80位浮点类型作为中间值.根据启用的优化设置和编译器详细信息,计算将以不同方式完成(具有不同的中间值),您将得到略微不同的结果.

#include <cstdio>

int main() {
  double x = 1.0;
  double y = x / 3.0;
  std::printf("x == y * 3.0: %s\n", x == y * 3.0 ? "true" : "false");
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

有了GCC,我看看false你是否编译-mfpmath=387 -O0.我看true是否我没有编译-mfpmath=387(这将默认为SSE而不是AMD64)或者如果我编译-O2.

您可以在GodBolt上看到如何使用x87指令编译它:https://godbolt.org/z/rf1Rir - 尝试添加-O2或删除-mfpmath=387它以查看它如何影响生成的代码.

请注意,这有点巧合(1.0 / 3.0) * 3.0 == 1.0.您可以在Python中测试以下代码,例如:

1.0 / 49.0 * 49.0 == 1.0
Run Code Online (Sandbox Code Playgroud)

这应该给False.