g++ (4.7.2) и подобни версии изглежда оценяват constexpr изненадващо бързо по време на компилиране. На моите машини всъщност много по-бързо от компилираната програма по време на изпълнение.
Има ли разумно обяснение за това поведение? Има ли включени техники за оптимизация, които са приложими само по време на компилиране, които могат да бъдат изпълнени по-бързо от действително компилирания код? Ако да, кое?
Ето моята тестова програма и наблюдаваните резултати.
#include <iostream>
constexpr int mc91(int n)
{
return (n > 100)? n-10 : mc91(mc91(n+11));
}
constexpr double foo(double n)
{
return (n>2)? (0.9999)*((unsigned int)(foo(n-1)+foo(n-2))%100):1;
}
constexpr unsigned ack( unsigned m, unsigned n )
{
return m == 0
? n + 1
: n == 0
? ack( m - 1, 1 )
: ack( m - 1, ack( m, n - 1 ) );
}
constexpr unsigned slow91(int n) {
return mc91(mc91(foo(n))%100);
}
int main(void)
{
constexpr unsigned int compiletime_ack=ack(3,14);
constexpr int compiletime_91=slow91(49);
static_assert( compiletime_ack == 131069, "Must be evaluated at compile-time" );
static_assert( compiletime_91 == 91, "Must be evaluated at compile-time" );
std::cout << compiletime_ack << std::endl;
std::cout << compiletime_91 << std::endl;
std::cout << ack(3,14) << std::endl;
std::cout << slow91(49) << std::endl;
return 0;
}
време на компилиране:
time g++ constexpr.cpp -std=c++11 -fconstexpr-depth=10000000 -O3
real 0m0.645s
user 0m0.600s
sys 0m0.032s
време на изпълнение:
time ./a.out
131069
91
131069
91
real 0m43.708s
user 0m43.567s
sys 0m0.008s
Тук mc91 е обичайният mac carthy f91 (както може да се намери в wikipedia), а foo е просто безполезна функция, връщаща реални стойности между около 1 и 100, с fib сложност по време на изпълнение.
Както бавното изчисление на 91, така и функциите на ackermann се оценяват с едни и същи аргументи от компилатора и компилираната програма.
Изненадващо, програмата дори би работила по-бързо, просто генерирайки код и го пускайки през компилатора, отколкото изпълнявайки самия код.