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

C++ c++;exp函数在i7-3770和i7-4790上x64下的不同结果,c++,64-bit,precision,exp,C++,64 Bit,Precision,Exp,当我用下面的代码执行一个简单的x64应用程序时,我在装有i7-3770和i7-4790 CPU的Windows PC上得到了不同的结果 #include <cmath> #include <iostream> #include <limits> void main() { double val = exp(-10.240990982718174); std::cout.precision(std::numeric_limits<double&g

当我用下面的代码执行一个简单的x64应用程序时,我在装有i7-3770和i7-4790 CPU的Windows 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-4790上的结果:

3.5677476354876413e-05
当我修改代码以调用

unsigned int control_word;
_controlfp_s(&control_word, _RC_UP, MCW_RC);
在exp函数调用之前,两个CPU都提供相同的结果

我的问题是:

  • 有人知道i7-3770和i7-4790之间差异的原因吗
  • <> LI>是否有一种方法可以在整个项目的VisualStudio 2015/2017 C++项目中设置浮点精度或一致性,而不只是用于以下函数调用?“浮点模型”设置(/fp)对此处的结果没有任何影响
假设double是使用IEEE-754编码的,并且使用此代码,您可以看到:

3.5677476354876406e-05以六进制表示为0x3F02B48CC0D0ABA8 3.5677476354876413e-05以六进制表示为0x3F02B48CC0D0ABA9


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

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

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

我还向VisualStudio社区发布了这个问题。我得到的信息是,Haswell和更新的CPU使用FMA3。您可以在程序开始时使用\u set\u FMA3\u enable(0)禁用此功能。当我这样做时,结果是相同的。

根据前20个左右的数字应该是0.0000356677476354876 393107(我添加了一个空格来显示数字开始发散的位置)。第一个结果稍微接近。与问题无关,但
main
返回int,而不是void。几乎可以肯定,在您的进程中注入了一个邪恶的DLL,它改变了控制字。请注意,
\u RC\u UP
不是默认值,它是
\u RC\u NEAR
。所以不管你认为什么“好”的机器实际上是麻烦制造者。查找该DLL可以让您忙碌一段时间。这是一种磁盘格式能够更快地解决的问题,特别是当不是你必须这样做的时候。我知道这不是默认行为。但这是我目前发现的唯一一种可能,它在两种CPU类型上都给出了相同的结果。此外,我在更多具有不同CPU的PC上尝试了此方法,我得到的印象是,所有具有Ivy Bridge和以前的CPU的PC都提供相同的结果(3.5677476354876406e-05),所有Haswell和以后的CPU也提供相同的结果(3.5677476354876413e-05)。有没有可能,x64下以Haswell四舍五入开始的双精度值已更改。此处记录了可能的重复情况“默认情况下,在x64平台上,CRT启动代码检测CPU是否支持FMA3指令,并启用或禁用库中的FMA3实现。”
unsigned int control_word;
_controlfp_s(&control_word, _RC_UP, MCW_RC);