Следующий код, скомпилированный с clang
, работает почти в 60 раз быстрее, чем тот, скомпилированный с помощью gcc
с одинаковыми флагами компилятора (либо -O2
, либо -O3
):
#include <iostream>
#include <math.h>
#include <chrono>
#include <limits>
long double func(int num)
{
long double i=0;
long double k=0.7;
for(int t=1; t<num; t++){
for(int n=1; n<16; n++){
i += pow(k,n);
}
}
return i;
}
int main()
{
volatile auto num = 3000000; // avoid constant folding
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
auto i = func(num);
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed = end-start;
std::cout.precision(std::numeric_limits<long double>::max_digits10);
std::cout << "Result " << i << std::endl;
std::cout << "Elapsed time is " << elapsed.count() << std::endl;
return 0;
}
Я тестировал это с тремя версиями gcc
4.8.4/4.9.2/5.2.1
и двумя версиями clang
3.5.1/3.6.1
, и вот тайминг на моей машине (для gcc 5.2.1
и clang 3.6.1
):
Сроки -O3
:
gcc: 2.41888s
clang: 0.0396217s
Сроки -O2
:
gcc: 2.41024s
clang: 0.0395114s
Сроки -O1
:
gcc: 2.41766s
clang: 2.43113s
Итак, кажется, что gcc
вообще не оптимизирует эту функцию даже на более высоких уровнях оптимизации. Вывод сборки clang
составляет почти около 100 строк дольше, чем gcc
, и я не думаю, что это необходимо, чтобы опубликовать его здесь, все, что я могу сказать, заключается в том, что на выходе сборки gcc
есть вызов pow
который не появляется в сборке clang
, предположительно потому, что clang
оптимизирует его до кучи внутренних вызовов.
Поскольку результаты идентичны (т.е. i = 6966764.74717416727754
), возникает вопрос:
- Почему
gcc
не может оптимизировать эту функцию, еслиclang
может? - Измените значение
k
на1.0
иgcc
станет таким же быстрым, есть ли арифметическая проблема с плавающей запятой, которуюgcc
не может пропустить?
Я попробовал static_cast
ing и включил предупреждения, чтобы узнать, есть ли какая-либо проблема с неявными преобразованиями, но на самом деле.
Обновление: Для полноты здесь приведены результаты для -Ofast
gcc: 0.00262204s
clang: 0.0013267s
Дело в том, что gcc
не оптимизирует код при O2/O3
.