当前位置: 首页 > 知识库问答 >
问题:

编译时怎么能比运行时(指数级)快呢?

杜轩昂
2023-03-14

下面的代码通过指数慢的算法计算斐波那契数:

#include <cstdlib>
#include <iostream>

#define DEBUG(var) { std::cout << #var << ": " << (var) << std::endl; }

constexpr auto fib(const size_t n) -> long long
{
    return n < 2 ? 1: fib(n - 1) + fib(n - 2);
}

int main(int argc, char *argv[])
{
    const long long fib91 = fib(91);

    DEBUG( fib91 );
    DEBUG( fib(45) );

    return EXIT_SUCCESS;
}

我在运行时计算第45个斐波那契数,在编译时计算第91个。

有趣的事实是,GCC4.9编译代码并在几分之一秒内计算出fib91,但吐出fib(45)需要一段时间。

以上是否意味着GCC会生成fib函数的两个编译版本,其中一个是快的,另一个是指数级慢的?

问题不是编译器如何优化fib(91)计算(是的!它确实使用了某种记忆),而是如果它知道如何优化fib函数,为什么它不对fib(45)做同样的操作呢?并且,fib函数有两个单独的编译吗?一个慢一个快?

共有1个答案

杜元明
2023-03-14

GCC可能正在记忆constexpr函数(启用fib(n))的JADEN(n)计算)。编译器这样做是安全的,因为constexpr函数是纯函数的。

将(n)“编译器算法”(使用memoization)与(?n)运行时算法(其中?是黄金比例)进行比较,突然之间,编译器的速度快得多就变得非常有意义了。

从cppreference上的constexpr页面(着重号为后加):

constexpr auto compute_fib(const size_t n) -> long long
{
    return n < 2 ? n : compute_fib(n - 1) + compute_fib(n - 2);
}

template <std::size_t N>
struct fib
{
    static_assert(N >= 0, "N must be nonnegative.");
    static const long long value = compute_fib(N);
};

在代码的其余部分中,您可以访问fib<45>::valuefib<91>::value,并保证在编译时对它们进行计算。

 类似资料:
  • 问题内容: 我听说在某些情况下,由于JIT优化,Java程序或Java程序的某些部分比C ++(或其他预编译的代码)中的“相同”代码执行得更快。这是由于编译器能够确定某些变量的范围,避免某些条件并在运行时提取类似的技巧。 您能否举一个(或更佳的)例子,在哪里适用?也许概述了编译器能够优化字节码的确切条件,超出了预编译代码的范围? 注意: 此问题 不是 关于将Java与C ++进行比较。关于JIT编

  • 发生在运行时,因为编译器不能在决定执行哪个函数,但为什么编译器不能在编译时决定呢? 产出: 狗在吃...

  • 例如如下代码: SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); Date date = sdf.parse("abcd"); 这段代码会抛出ParseException,而它是编译时异常,为什么编译阶段不报错,运行时报错?

  • 这两个类路径能完全不同吗?

  • 问题内容: 何时加载静态变量,运行时或编译时?有人可以解释一下吗? 我非常感谢您的帮助。 谢谢。 问题答案: 它们在运行时加载。 静态表示:该变量属于该类,而不属于该类的实例。因此,每个静态变量只有一个值,如果您有该类的n个实例,则没有n个值。

  • 问题内容: 专业人士使用这两种方式的缺点是什么? 我实际上在Netbeans的“项目属性”>“ Java应用程序的库”中看到了它。我们有两个选项卡,一个用于编译时间库和运行时库,看起来我们可以将一个库添加到彼此独立的一个库中 问题答案: “库属性”对话框的用户界面和术语非常混乱。 该对话框上的“帮助”按钮将为您提供一些信息。 编译时库列表可以是运行时库列表的子集。 考虑这种情况… 您具有从库“ w