c++ exp 函数在 i7-3770 和 i7-4790 上 x64 下的不同结果

c++ exp function different results under x64 on i7-3770 and i7-4790

当我使用以下代码执行一个简单的 x64 应用程序时,我在 Windows 配备 i7-3770 和 i7-4790 CPU 的 PC 上得到不同的结果

#include <cmath>
#include <iostream>
#include <limits>

void main()
{
  double val = exp(-10.240990982718174);
  std::cout.precision(std::numeric_limits<double>::max_digits10);
  std::cout << val;
}

i7-3770 上的结果:

3.5677476354876406e-05

i7-4790 上的结果:

3.5677476354876413e-05

当我修改代码调用

unsigned int control_word;
_controlfp_s(&control_word, _RC_UP, MCW_RC);

在调用 exp 函数之前,两个 CPU 都提供相同的结果。

我的问题:

假设 double 使用 IEEE-754 编码,并使用这个 decimal to binary converter,你可以看到:

3.5677476354876406e-05 is represented in hexa as 0x3F02B48CC0D0ABA8 3.5677476354876413e-05 is represented in hexa as 0x3F02B48CC0D0ABA9

仅在最后一位不同,可能是由于舍入错误。

我做了一些进一步的调查,发现了以下事实:

  • 使用不同的编译器 (Intel)Windows 时也会出现此问题
  • 在 linux 系统上两个值相等

我也将这个问题发布到 Visual Studio 社区。我得到的信息是,Haswell 和更新的 CPU 使用 FMA3。您可以在程序开头使用 _set_FMA3_enable(0) 禁用此功能。当我这样做时,结果是一样的。