How can the compile-time be (exponentially) faster than run-time?

前端 未结 3 2048
面向向阳花
面向向阳花 2020-12-28 12:21

The below code calculates Fibonacci numbers by an exponentially slow algorithm:

#include 
#include 

#define DEBUG(va         


        
3条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-28 12:42

    GCC is likely memoizing constexpr functions (enabling a Θ(n) computation of fib(n)). That is safe for the compiler to do because constexpr functions are purely functional.

    Compare the Θ(n) "compiler algorithm" (using memoization) to your Θ(φn) run time algorithm (where φ is the golden ratio) and suddenly it makes perfect sense that the compiler is so much faster.

    From the constexpr page on cppreference (emphasis added):

    The constexpr specifier declares that it is possible to evaluate the value of the function or variable at compile time.

    The constexpr specifier does not declare that it is required to evaluate the value of the function or variable at compile time. So one can only guess what heuristics GCC is using to choose whether to evaluate at compile time or run time when a compile time computation is not required by language rules. It can choose either, on a case-by-case basis, and still be correct.

    If you want to force the compiler to evaluate your constexpr function at compile time, here's a simple trick that will do it.

    constexpr auto compute_fib(const size_t n) -> long long
    {
        return n < 2 ? n : compute_fib(n - 1) + compute_fib(n - 2);
    }
    
    template 
    struct fib
    {
        static_assert(N >= 0, "N must be nonnegative.");
        static const long long value = compute_fib(N);
    };
    

    In the rest of your code you can then access fib<45>::value or fib<91>::value with the guarantee that they'll be evaluated at compile time.

提交回复
热议问题