简短的问题:
在 FPU 上设置 _EM_INVALID 异常标志如何导致不同的值?
长问题:
在我们的项目中,我们在 Release 构建中关闭了浮点异常,但在 Debug 构建中使用 _controlfp_s() 打开了 ZERODIVIDE、INVALID 和 OVERFLOW。这是为了捕获错误(如果存在)。
但是,我们也希望数值计算的结果(包括优化算法、矩阵求逆、蒙特卡洛和各种事情)在 Debug 和 Release 构建之间保持一致,以使调试更容易。
我希望 FPU 上异常标志的设置不应该影响计算值 - 仅影响是否抛出异常。但是在通过我们的计算向后工作之后,我可以隔离下面的代码示例,该示例显示调用 log() 函数时最后一位存在差异。
这会传播到结果值的 0.5% 差异。
下面的代码将在将其添加到 Visual Studio 2005、Windows XP 中的新解决方案并在调试配置中编译时给出显示的程序输出。(Release 会给出不同的输出,但那是因为优化器重用了第一次调用 log() 的结果。)
我希望有人可以对此有所了解。谢谢。
/*
Program output:
Xi, 3893f76f, 7.4555176582633598
K, c0a682c7, 7.44466687218
Untouched
x, da8caea1, 0.0014564635732296288
Invalid exception on
x, da8caea2, 0.001456463573229629
Invalid exception off
x, da8caea1, 0.0014564635732296288
*/
#include <float.h>
#include <math.h>
#include <limits>
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
unsigned uMaskOld = 0;
errno_t err;
cout << std::setprecision (numeric_limits<double>::digits10 + 2);
double Xi = 7.4555176582633598;
double K = 7.44466687218;
double x;
cout << "Xi, " << hex << setw(8) << setfill('0') << *(unsigned*)(&Xi) << ", " << dec << Xi << endl;
cout << "K, " << hex << setw(8) << setfill('0') << *(unsigned*)(&K) << ", " << dec << K << endl;
cout << endl;
cout << "Untouched" << endl;
x = log(Xi/K);
cout << "x, " << hex << setw(8) << setfill('0') << *(unsigned*)(&x) << ", " << dec << x << endl;
cout << endl;
cout << "Invalid exception on" << endl;
::_clearfp();
err = ::_controlfp_s(&uMaskOld, 0, _EM_INVALID);
x = log(Xi/K);
cout << "x, " << hex << setw(8) << setfill('0') << *(unsigned*)(&x) << ", " << dec << x << endl;
cout << endl;
cout << "Invalid exception off" << endl;
::_clearfp();
err = ::_controlfp_s(&uMaskOld, _EM_INVALID, _EM_INVALID);
x = log(Xi/K);
cout << "x, " << hex << setw(8) << setfill('0') << *(unsigned*)(&x) << ", " << dec << x << endl;
cout << endl;
return 0;
}