【问题标题】:GCC optimization of iterative functions迭代函数的 GCC 优化
【发布时间】:2015-04-25 16:08:04
【问题描述】:

对于递归和迭代版本,我有以下斐波那契代码:

#include <stdio.h>

typedef long long INT;

long long recursive (long long i) {
    if (i == 0) return 0;
    if (i == 1) return 1;
    return recursive (i-1) + recursive (i-2);
}


long long iterative (long long i) {
    INT counter = i-1;
    INT fib1 = 0;
    INT fib2 = 0;

    // first iteration
    fib1 = 0;
    fib2 = 1;

    while (counter > 0) {
        INT temp1 = fib1;
        INT temp2 = fib2;
        fib1 = fib2;
        fib2 = temp1 + temp2;

        counter--;
    }

}

int main (int argc, char **argv) {

    printf("Result: %lli\n", iterative(10));

    return 0;
}

我尝试使用 GCC -O2 优化对其进行编译,以查看递归是否会比迭代执行得更好,但我注意到一个有趣的现象:使用 -O2 编译时,迭代函数输出 0 而如果编译时不带标志,它输出正确的数字。

gcc -O2 fibonacci.c -o fib &amp;&amp; ./fib: Result: 0

gcc fibonacci.c -o fib &amp;&amp; ./fib: Result: 55

【问题讨论】:

  • 你不会在迭代中返回结果。
  • ... 这给了你未定义的行为。打开这些警告! -Wall -Wextra -Werror -pedantic -std=c99(或其他标准版本)
  • 是的,就是这样。那么为什么我在没有优化的情况下编译它会起作用呢?
  • 这就是未定义行为的作用。任何事情都有可能发生。当函数实际上没有返回任何东西时,包括一个给出你期望的结果的函数。
  • 而且你没有对递归和迭代进行公平的比较。当结果为 n 时,递归斐波那契实现使 n 次递归调用递归 (1)。

标签: c gcc optimization


【解决方案1】:

递归将比迭代或尾递归版本慢(通常会针对迭代版本进行优化)。两者的例子都在这个线程中:

Fibonacci Computation Time

【讨论】:

    【解决方案2】:

    您的迭代循环也不是最理想的,它使用了比需要更多的分配。这样就足够了:

    int sum = fib1 + fib2;
    fib1 = fib2;
    fib2 = sum;
    

    当然,您可以在开始时为 fib1/fib2 分配初始值,而不是先初始化为 0,然后再分配。

    【讨论】:

    • 那些是相关的样式cmets,但显然编译器知道它没有区别。
    【解决方案3】:

    你不是return-ing 来自long long iterative (long long i) 的任何东西。你应该在每个非void 函数的末尾放置一个return 语句,否则你会得到UB(未定义的行为)。

    但是,该函数仍可能“返回”某些内容。它将“返回”处理器寄存器中用于从函数返回值的任何内容,这可能是您对return 的意思,也可能不是。

    【讨论】:

      猜你喜欢
      • 2017-12-24
      • 1970-01-01
      • 2021-06-10
      • 1970-01-01
      • 2011-12-16
      • 2015-01-16
      • 2020-07-14
      • 1970-01-01
      • 2021-06-10
      相关资源
      最近更新 更多