我编写了以下代码来测试constexpr析因与正常方式评估所用的时间
#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;
}
当我运行代码时,我正在
Now calling the constexpr
1932053504
Now calling the normal
1932053504
Elapsed time for constexpr is 81812 Elapsed time for normal is 72428
但是constexpr
应该花费近乎“0”的时间,因为它已经在编译期间计算过了。
但令人惊讶的是constexpr
计算需要比正常因子工作更多的时间。
我试图关注this问题,但我无法理解我的背景中的答案。
请帮我理解。
我编译了代码(filename是constexpr.cpp)
g++ --std=c++11 constexpr.cpp
在@rici输入后,我确实将第18行更改为
const long int x =13;
结果现在是
Now calling the constexpr
1932053504
Now calling the normal
1932053504
Elapsed time for constexpr is 114653 Elapsed time for normal is 119052
似乎有一次我提到x为const,编译器在编译时计算 factorialC
我在Windows上使用MinGW32的4.9.3版g ++
答案 0 :(得分:8)
问题在于constexpr
保证在编译时进行评估。关键字constexpr
只是说可以,但编译器也可以在运行时自由评估它,因为它认为合适。
运行时间的差异可能是因为你1)做得不够(一次迭代什么都没有)和2)递归没有迭代那么快(我认为,虽然差异很小)。
为了保证编译时评估,您必须在编译器必须在编译时对其进行评估的上下文中使用它,例如模板:
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();
evaluate
,std::integral_constant
还有一个标准库函数。你可以改用它。
答案 1 :(得分:2)
long int x = 13;
这不是一个常量表达式,因此编译器无法在编译时评估factorial(x);
。
尝试向其发送常量值,例如constexpr
值,以便进行评估:
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;
}
顺便说一下,在谈论表演时,你应该把苹果与苹果相提并论。
答案 2 :(得分:1)
注意,它不能在编译时计算,因为编译器对此函数中long int x
的值一无所知:
constexpr long int factorialC(long int x)
如果您想要编译时间因子,则可以使用模板。类似的东西:
#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;
}