Следующий код, скомпилированный с 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.