Короткий вопрос:
Как установка флага исключения _EM_INVALID на FPU может привести к другим значениям?
Длинный вопрос:
В нашем проекте мы отключили исключения с плавающей запятой в нашей сборке Release, но включили ZERODIVIDE, INVALID и OVERFLOW, используя _controlfp_s () в нашей сборке Debug. Это для того, чтобы выявлять ошибки, если они есть.
Однако мы также хотели бы, чтобы результаты численных расчетов (включая алгоритмы оптимизации, инверсию матриц, Монте-Карло и все такое) были согласованы между сборкой отладки и выпуска, чтобы упростить отладку.
Я ожидал, что установка флагов исключения на 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;
}