c++ - 为什么低效的阶乘计算是......高效(且快速)?

标签 c++ recursion memoization

我写了这个简单的程序来测试 memoization技术:

int main() {
    function<double(double)> f = [&f](double i) -> double {
        if (i == 1)
            return 1;
        else
            return i * f(i - 1);
    };
    cout << f(100) << endl;
}

我期望在几秒钟内执行这段代码(因为它的递归效率低下),但实际上只花了几毫秒......为什么?我认为引擎盖下有一些编译器优化,但我不明白会发生什么。

奖励问题: 您能否给我一个执行效率低下(编译器优化与否)的简单程序,以便我测试记忆化的好处?

最佳答案

内存技术旨在用于优化昂贵的函数调用。阶乘函数并非如此。 C++ 非常快,因此阶乘函数调用的计算时间永远不会超过几毫秒。 (至少如果不使用多精度)。 factorial(100) 是“仅”100 次乘法,因此对于 C++ 来说没有任何意义。

如果这只是为了测试或演示目的,我会简单地在函数调用中引入延迟( sleep 、长虚拟循环或其他)。 随着内存的实现,这种延迟不应该发生,所以它“几乎”立即运行。

这是我会做的一个例子。 factorial 是昂贵的函数。 memo_factorial 是它的包装,实现了内存技术。 在函数的第一次调用中,输入和输出的字典被更新,在接下来的具有相同输入的调用中,先前存储的值被返回,所以“真正的”函数不会再次执行。

#define ELAPSE(cmd) { clock_t s = clock();\
    long ret = cmd;\
    cout << "\t" << #cmd\
         << " = " << ret \
         << "\t(" << (clock()-s)/double(CLOCKS_PER_SEC) << " secs)" \
         << endl; }

long factorial(long i) {
    for(clock_t s = clock(); (clock()-s)<CLOCKS_PER_SEC; );
    return i<=1 ? 1 : i*factorial(i-1);
}
long memo_factorial(long i) {
    static map<long,long> saved;
    map<long,long>::const_iterator it = saved.find(i);
    return ( it==saved.end() ) ? (saved[i] = memo_factorial(i)) : it->second;
}

int main() {
    cout << "first execution WITHOUT memoization" << endl;
    for(int i=1; i<5; ++i) {
        ELAPSE( memo_factorial(i) )
    }

    cout << "second execution WITH memoization" << endl;
    for(int i=1; i<5; ++i) {
        ELAPSE( memo_factorial(i) )
    }

    return 0;
}

输出应该是:

first execution WITHOUT memoization
    memo_factorial(i) = 1   (1 secs)
    memo_factorial(i) = 2   (1 secs)
    memo_factorial(i) = 6   (1 secs)
    memo_factorial(i) = 24  (1 secs)
second execution WITH memoization
    memo_factorial(i) = 1   (0 secs)
    memo_factorial(i) = 2   (0 secs)
    memo_factorial(i) = 6   (0 secs)
    memo_factorial(i) = 24  (0 secs)

希望你觉得它有用。

问候, 亚历克斯

注意:阶乘通常定义在整数值上。当然,它只是一个乘法序列,因此可以应用于其他类型。

关于c++ - 为什么低效的阶乘计算是......高效(且快速)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36736404/

相关文章:

python - 为什么一种内存策略比另一种慢?

c++ - 优化器会根据编译时常量推导出数学表达式吗?

c++ - 我在哪里可以找到 std::string 的实现

algorithm - 分析算法-递归方程(汉诺塔)

javascript - 简单的 React 组件抛出 "too much recursion"错误

arrays - 为什么 Swift 字典在内存过程中比数组慢得多

algorithm - 这个硬币找零算法的时间复杂度是多少?

c++ - MFC中的OwnerDrawn控件

c++ - 两个数组之间最近点的索引

java - Haskell 完整的文本文件索引器