constexpr在运行时表现更差

时间:2016-09-19 16:27:58

标签: c++ performance c++11 constexpr

我编写了以下代码来测试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   

V2: -

在@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 ++

3 个答案:

答案 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();

evaluatestd::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;
 }