Численная регрессия в x64 с компилятором VS2013 с последними чипами Haswell?

Недавно мы начали видеть, что единичные тесты терпят неудачу на нашей машине сборки (некоторые численные вычисления вышли из толерантности). По результатам расследования мы обнаружили, что некоторые из наших разработчиков не смогли воспроизвести отказ теста. Чтобы сократить длинную историю, мы в конечном итоге отследили проблему до того, что, по-видимому, было ошибкой округления, но эта ошибка возникала только при сборке x64 на последних чипах Haswell (к которым недавно был добавлен наш сервер сборки). Мы сузили его и вытащили один расчет из одного из наших тестов:

#include "stdafx.h"
#include <cmath>

int _tmain(int argc, _TCHAR* argv[])
{
  double rate = 0.0021627412080263146;
  double T = 4.0246575342465754;
  double res = exp(-rate * T);
  printf("%0.20e\n", res);
  return 0;
}

Когда мы скомпилируем этот x64 в VS2013 (с переключателями компилятора по умолчанию, включая /fp:precise), он дает разные результаты на чипе Sandy Bridge и более новом чипе Haswell. Разница заключается в 15-й значащей цифре, которая, как мне кажется, находится за пределами машины epsilon для двойного использования на обеих машинах).

Если мы скомпилируем тот же код в VS2010 или VS2012 (или, кстати, VS2013 x86), мы получим тот же ответ на оба чипа.

В последние несколько лет мы прошли через многие версии Visual Studio и множество различных чипов Intel для тестирования, и никто не может вспомнить, что нам когда-либо приходилось корректировать наши ожидания тестирования регрессии на основе различных ошибок округления между фишками.

Это, очевидно, привело к игре бит-моль между разработчиками с более старым и новым оборудованием в отношении того, что должно быть ожиданием тестов...

Есть ли в VS2013 параметр компилятора, который нам нужно использовать, чтобы как-то смягчить несоответствие?

Обновление:

Results on Sandy Bridge developer PC:
VS2010-compiled-x64: 9.91333479983898980000e-001
VS2012-compiled-x64: 9.91333479983898980000e-001
VS2013-compiled-x64: 9.91333479983898980000e-001

Results on Haswell build server:
VS2010-compiled-x64: 9.91333479983898980000e-001
VS2012-compiled-x64: 9.91333479983898980000e-001
VS2013-compiled-x64: 9.91333479983899090000e-001

Update:

Я использовал procexp для захвата списка DLL, загруженных в тестовую программу.

Sandy Bridge developer PC:
apisetschema.dll
ConsoleApplication8.exe
kernel32.dll
KernelBase.dll
locale.nls
msvcr120.dll
ntdll.dll

Haswell build server:
ConsoleApplication8.exe
kernel32.dll
KernelBase.dll
locale.nls
msvcr120.dll
ntdll.dll

Ответы

Ответ 1

Результаты, задокументированные вами, зависят от значения регистра MXCSR, здесь важны два бита, которые выбирают режим округления. Чтобы получить "счастливый" номер, который вам нравится, вам нужно заставить процессор округлить. Вот так:

#include "stdafx.h"
#include <cmath>
#include <float.h>

int _tmain(int argc, _TCHAR* argv[]) {
    unsigned prev;
    _controlfp_s(&prev, _RC_DOWN, _MCW_RC);
    double rate = 0.0021627412080263146;
    double T = 4.0246575342465754;
    double res = exp(-rate * T);
    printf("%0.20f\n", res);
    return 0;
}

Выход: 0.99133347998389898000

Измените _RC_DOWN на _RC_NEAR, чтобы MXCSR работал в обычном режиме округления, как программа запускает ее перед запуском вашей программы. Который производит 0.99133347998389909000. Или, другими словами, ваши машины Haswell на самом деле производят ожидаемое значение.

Точно, как это произошло, может быть очень сложно диагностировать, контрольный регистр - наихудшая возможная глобальная переменная, о которой вы можете думать. Обычной причиной является инъецированная DLL, которая перепрограммирует FPU. Отладчик может отображать загруженные библиотеки DLL, сравнивать списки между двумя машинами, чтобы найти кандидата.

Ответ 2

Из-за ошибки в коде CRT x64 CRT для MS 2013 неверно обнаруживается поддержка AVX и FMA3.

Исправлено в обновленной версии среды 2013 или с использованием новой версии MSVC или просто отключено поддержка функций во время выполнения, вызывая "_set_FMA3_enable (0);".

См: https://support.microsoft.com/en-us/help/3174417/fix-programs-that-are-built-in-visual-c-2013-crash-with-illegal-instruction-exception