NaN с плавающей точкой в ​​зависимости от некоррелированной обработки исключений в переполнении стека

Очень странно:

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. ОС 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: Когда я установил /fp:strict переключиться в C ++ / генерацию кода, результат такой же с Debug + Win32, но с Release + Win32 он меняется на c = a * b; // NaN а также c = (1/sigma) * exp(-1/sigma); // 0 независимо от того, с попыткой или нет. Я не понимаю, почему это остается NaN+NaN с Debug + Win32 и без предыдущей попытки. Как отладить программу, которая должна быть безопасной с плавающей запятой, когда результаты отличаются независимо /fp:strict от релиза в зависимости от предыдущей попытки?

Редактировать 3Здесь полная программа:

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

1

Решение

Подобные вещи могут происходить из-за различий в распределении / использовании регистров. Например — с блоком try-catch значение sigma может быть сохранен как 64-битный double затем загружается из памяти, в то время как без блока может использоваться 80-битный регистр с более высокой точностью (см. http://en.wikipedia.org/wiki/Extended_precision) без округления до 64 бит. Я предлагаю вам проверить свою сборку, если вам не все равно.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]