c++exceptionfloating-pointnanextended-precision

Floating-point NaN depending on uncorrelated exception handling in C++


Really weird:

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;

Ok, the second c result could be 0 because of some optimization.

BUT: when I delete the try/catch block, the second c remains NaN! Why this different behaviour??? My compiler is VC++ 2010 Express. OS Windows 7 64-bit. I use only standard libs like iostream and cmath.

Edit: my first observation was with Debug+Win32 default settings for an empty console application. With Release+Win32 the results are: first c 0, second c NaN - no matter if try/catch present or not! Summary:

                                 //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

Edit 2: When I set the /fp:strict switch in C++/codegeneration, the result is same with Debug+Win32, but with Release+Win32 it changes to c = a * b; // NaN and c = (1/sigma) * exp(-1/sigma); // 0 no matter if with try or not. I don't get why it stays NaN+NaN with Debug+Win32 and no preceding try. How to debug a program that has to be floating-point safe, when results differ dispite /fp:strict from Release depending on preceding try?

Edit 3: Here a full program:

// On VC++ 2010 Express in default Win32-Debug mode for empty console application.
// OS: Windows 7 Pro 64-Bit, CPU: Intel Core i5.
// Even when /fp:strict is set, same behaviour.
//
// Win32-Release mode: first c == 0, second c == NaN (independent of try)
// with /fp:strict: first c == NaN, second c == 0 (also independent of try)

#include <iostream>
#include <cmath>

using namespace std;

int main()
{
    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 with preceding try or
    cout << c << endl;              // NaN without preceding try

    cin.get();
    return 0;
}

Solution

  • These sorts of things can happen due to differences in register allocation/usage. For example - with the try-catch block, the value of sigma may be being saved as a 64-bit double then reloaded from memory, while without the block it may use a higher-precision 80-bit register (see http://en.wikipedia.org/wiki/Extended_precision) without rounding to 64 bits. I suggest you check your assembly if you care.