浮点NaN取决于C ++中不相关的异常处理

时间:2013-11-19 09:50:43

标签: c++ exception-handling floating-point nan extended-precision

真的很奇怪:

double *data; // uncorrelated
double a,b,c;
double sigma = 1e-309; // denormalized number

try { data = new double[10]; } // uncorrelated
catch(...) { cout << "error"; return 1; }

a = 1/sigma;                    // infinite
b = exp(-1/sigma);              // 0
c = a * b;                      // NaN
cout << c << endl;
c = (1/sigma) * exp(-1/sigma);  // 0
cout << c << endl;

好的,由于一些优化,第二个c结果可能是0。

但是:当我删除try / catch块时,第二个c仍然是NaN!为何这种不同的行为?我的编译器是VC ++ 2010 Express。 OS Windows 7 64位。我只使用像iostream和cmath这样的标准库。

编辑:我的第一个观察是针对空控制台应用程序的Debug + Win32默认设置。使用Release + Win32,结果是:第一个c 0,第二个c NaN - 无论是否存在try / catch!总结:

                                 //Debug+Win32              // Release+Win32
                              //with try   //without     //with try   //without
c = a * b;                     // NaN         NaN             0           0
c = (1/sigma) * exp(-1/sigma); // 0           NaN            NaN         NaN

编辑2 :当我在C ++ / codegeneration中设置/fp:strict开关时,结果与Debug + Win32相同,但使用Release + Win32时,它会更改为c = a * b; // NaNc = (1/sigma) * exp(-1/sigma); // 0无论是否尝试。我不知道为什么它与Debug + Win32保持NaN+NaN并没有先前的尝试。如果调试结果必须是浮点安全的,当结果与Release版本有所不同时,取决于前面的尝试?

编辑3 :这是一个完整的程序:

/fp:strict

1 个答案:

答案 0 :(得分:2)

由于寄存器分配/使用的差异,可能会发生这些事情。例如 - 使用try-catch块,sigma的值可能会被保存为64位double,然后从内存重新加载,而没有块,它可能会使用更高精度的80-位寄存器(见http://en.wikipedia.org/wiki/Extended_precision)而不舍入为64位。如果你愿意,我建议你检查你的装配。