g ++: оптимизация -march = haswell и более новые изменения числовой результат

Я работал над оптимизацией производительности и, конечно, проводил регрессионные тесты, когда заметил, что g ++, похоже, меняет результаты в зависимости от выбранной оптимизации. До сих пор я думал, что -O2 -march=[whatever] должны давать одинаковые результаты для численных расчетов независимо от того, какая архитектура выбрана. Однако, похоже, это не относится к g ++. Хотя использование старых архитектур вплоть до ivybridge дает те же результаты, что и clang для любой архитектуры, я получаю разные результаты для gcc для haswell и новее. Это ошибка в gcc или я что-то не так понял по поводу оптимизации? Я действительно поражен, потому что Clang, кажется, не показывает такое поведение.

Обратите внимание, что я хорошо знаю, что различия находятся в пределах точности машины, но они все еще мешают моим простым проверкам регрессии.

Вот пример кода:

#include <iostream>
#include <armadillo>

int main(){
arma::arma_rng::set_seed(3);
arma::sp_cx_mat A = arma::sprandn<arma::sp_cx_mat>(20,20, 0.1);
arma::sp_cx_mat B = A + A.t();
arma::cx_vec eig;
arma::eigs_gen(eig, B, 1, "lm", 0.001);
std::cout << "eigenvalue: " << eig << std::endl;
}

Скомпилировано с использованием:

g++ -march=[architecture] -std=c++14 -O2 -o test example.cpp -larmadillo

версия gcc: 6.2.1

версия clang: 3.8.0

Скомпилировано для 64 бит, выполнено на процессоре Intel Skylake.

1

Решение

Это потому, что GCC по умолчанию использует инструкцию fused-multiply-add (fma), если она доступна. Clang, напротив, не использует их по умолчанию, даже если это доступно.

Результат от a*b+c Можно отличаться Используется ли fma или нет, поэтому вы получаете разные результаты, когда вы используете -march=haswell (Haswell — первый процессор Intel, поддерживающий fma).

Вы можете решить, хотите ли вы использовать эту функцию с -ffp-contract=XXX,

  • -ffp-contract=off, вы не получите FMA инструкции.
  • -ffp-contract=onВы получаете инструкции FMA, но только в случае сокращения, если это разрешено стандартом языка. В текущей версии GCC это означает отключение (поскольку оно еще не реализовано).
  • -ffp-contract=fast (это GCC по умолчанию), вы получите инструкции FMA.
4

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

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

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