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;
}
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.