I wrote the following code to test the time taken for a constexpr factorial to evaluate vs normal way
#include<iostream>
#include<chrono>
constexpr long int factorialC(long int x){ return x*(x <2?1 : factorialC(x-1));}
using ns = std::chrono::nanoseconds;
using get_time = std::chrono::steady_clock;
void factorial(long int x){
long int suma=1;
for(long int i=1; i<=x;i++)
{
suma=suma*i;
}
std::cout<<suma<<std::endl;
}
int main(){
long int x = 13;
std::cout<<"Now calling the constexpr"<<std::endl;
auto start1 = get_time::now();
std::cout<<factorialC(x)<<std::endl;
auto end1 = get_time::now();
std::cout<<"Now calling the normal"<<std::endl;
auto start2 = get_time::now();
factorial(x);
auto end2 = get_time::now();
std::cout<<"Elapsed time for constexpr is "<<std::chrono::duration_cast<ns>(end1-start1).count()
<<" Elapsed time for normal is "<<std::chrono::duration_cast<ns>(end2-start2).count()<<std::endl;
}
When I run the code I am getting
Now calling the constexpr
1932053504
Now calling the normal
1932053504
Elapsed time for constexpr is 81812 Elapsed time for normal is 72428
But constexpr
should take nearly "0" time because it has already been calculated during compilation time .
But surprisingly constexpr
calculation takes more time than a normal factorial to work.
I have tried to follow this question, but I am not able understand the answer in my context.
Please help me to understand it.
I compiled the code through (filename is constexpr.cpp)
g++ --std=c++11 constexpr.cpp
after @rici input, I did change line number 18 to
const long int x =13;
The results now are
Now calling the constexpr
1932053504
Now calling the normal
1932053504
Elapsed time for constexpr is 114653 Elapsed time for normal is 119052
It seems once I mentioned the x to be const, the compiler is calculating factorialC at compile time
I am using 4.9.3 version of g++ from MinGW32 on windows
The problem is that something constexpr
is not guaranteed to be evaluated at compile time. The keyword constexpr
just says that it can, but the compiler is free to evaluate it at run time too, as it sees fit.
The difference in run time is probably because you 1) aren't doing it enough (one iteration is nothing) and 2) recursion isn't as fast as iteration (I think, although the difference is minimal).
To guarantee compile time evaluation, you will have to use it in a context where the compiler has to evaluate it at compile time, something like a template for example:
template<unsigned long long n>
auto evaluate() { return n; }
//...
auto start1 = get_time::now();
std::cout << evaluate<factorialC(x)>() << std::endl; //factorialC is evaluted
//at compile timme
auto end1 = get_time::now();
There is also a standard library function for evaluate
, std::integral_constant
. You can use that instead.
long int x = 13;
That''s not a constant expression, so the compiler can't evaluate factorial(x);
at compile time.
Try to send it constant values, like a constexpr
value so it can do the evaluation:
int main(){
long int x = 13;
constexpr long y = 13;
std::cout << "Now calling the constexpr" << std::endl;
auto start1 = get_time::now();
// Notice the use of a constexpr value here!
std::cout << factorialC(y) << std::endl;
auto end1 = get_time::now();
std::cout << "Now calling the normal" << std::endl;
auto start2 = get_time::now();
// Simply call your function witha runtime value.
// Try to ensure that the compiler don't inline the obvious value of x
std::cout << factorialC(x) << std::endl;
auto end2 = get_time::now();
std::cout << "Elapsed time for constexpr is "
<< std::chrono::duration_cast<ns>(end1-start1).count()
<< " Elapsed time for normal is "
<< std::chrono::duration_cast<ns>(end2-start2).count()
<< std::endl;
}
By the way, you should compaire apples with apples when talking about performance.
Note, that it can not be computed at a compile time, because compiler does not know nothing about a value of a long int x
in this function:
constexpr long int factorialC(long int x)
If you want compile time factorial you can use templates instead. Something like:
#include <iostream>
template<int N> inline int factorial(){ return N*factorial<N-1>(); }
template<> inline int factorial<1>(){ return 1; }
int main()
{
std::cout << factorial<13>() << std::endl;
return 0;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With