我们最近开始看到构建机器上的单元测试失败(某些数值计算超出了容限)。经过调查,我们发现我们的一些开发人员无法重现测试失败。简而言之,我们最终追踪到了似乎是舍入误差的问题,但这个错误只发生在最新的Haswell芯片上的x64构建(我们的构建服务器最近升级到了这个版本)。我们缩小了范围,并从我们的一个测试中提取了一个计算:
#include "stdafx.h"
#include <cmath>
int _tmain(int argc, _TCHAR* argv[])
{
double rate = 0.0021627412080263146;
double T = 4.0246575342465754;
double res = exp(-rate * T);
printf("%0.20e\n", res);
return 0;
}
当我们在VS2013中编译这个x64 (使用默认的编译器开关,包括/fp:precise
)时,它在较旧的Sandy Bridge芯片和较新的Haswell芯片上给出了不同的结果。不同之处在于第15位有效数字,我认为它在两台机器上的机器epsilon之外)。
如果我们用VS2010或VS2012 (或者,顺便说一句,VS2013 x86)编译相同的代码,我们会在两个芯片上得到完全相同的结果。
在过去的几年里,我们经历了许多版本的Visual Studio和许多不同的Intel芯片进行测试,没有人记得我们曾经不得不根据芯片之间不同的舍入误差来调整我们的回归测试期望。
这显然导致了开发人员与旧硬件和新硬件之间的一场关于测试预期的博弈……
在VS2013中有没有一个编译器选项,我们需要使用它来以某种方式缓解这种差异?
更新:
Results on Sandy Bridge developer PC:
VS2010-compiled-x64: 9.91333479983898980000e-001
VS2012-compiled-x64: 9.91333479983898980000e-001
VS2013-compiled-x64: 9.91333479983898980000e-001
Results on Haswell build server:
VS2010-compiled-x64: 9.91333479983898980000e-001
VS2012-compiled-x64: 9.91333479983898980000e-001
VS2013-compiled-x64: 9.91333479983899090000e-001
更新:
我使用procexp捕获加载到测试程序中的DLL列表。
Sandy Bridge developer PC:
apisetschema.dll
ConsoleApplication8.exe
kernel32.dll
KernelBase.dll
locale.nls
msvcr120.dll
ntdll.dll
Haswell build server:
ConsoleApplication8.exe
kernel32.dll
KernelBase.dll
locale.nls
msvcr120.dll
ntdll.dll
发布于 2015-01-13 00:38:27
您记录的结果受MXCSR寄存器的值影响,此处选择舍入模式的两个位很重要。要获得您喜欢的“快乐”数字,您需要强制处理器向下舍入。如下所示:
#include "stdafx.h"
#include <cmath>
#include <float.h>
int _tmain(int argc, _TCHAR* argv[]) {
unsigned prev;
_controlfp_s(&prev, _RC_DOWN, _MCW_RC);
double rate = 0.0021627412080263146;
double T = 4.0246575342465754;
double res = exp(-rate * T);
printf("%0.20f\n", res);
return 0;
}
输出: 0.99133347998389898000
将_RC_DOWN
更改为_RC_NEAR
,以使MXCSR处于正常舍入模式,就像操作系统在启动程序之前对其进行编程一样。这会产生0.99133347998389909000。或者换句话说,您的Haswell机器实际上正在产生预期的值。
确切地说这是如何发生的是很难诊断的,控制寄存器是你能想到的最糟糕的全局变量。通常的原因是注入的DLL对FPU进行了重新编程。调试器可以显示加载的DLL,比较两台机器之间的列表以找到候选者。
发布于 2017-03-21 04:52:15
由于MS 2013 CRT x64 CRT代码不能正确检测AVX和FMA3支持的错误。
已在更新的2013运行时修复,或使用较新的MSVC版本,或仅在运行时通过调用“"_set_FMA3_enable(0);”“禁用功能支持。
https://stackoverflow.com/questions/27905307
复制相似问题