这个尾递归即使是逻辑 - 并且存在吗?

时间:2013-12-23 10:31:41

标签: c recursion tail-recursion

我知道这个标题与Is this tail-recursion?重复,但这是不同的,我无法从上一个问题中得到线索。所以我得再问一次。

代码:

int sum_n(int n, int *sum)
{
    return n && (*sum += n) && sum_n(n - 1, sum);
}

据说(外语源)尾递归有两个特点:

  1. 该功能是自称的
  2. 只需要不断的堆栈空间
  3. 这两个特征是判断尾递归的唯一关键因素吗?返回语句中的逻辑运算符&&是否会影响尾递归?

    最重要的是,是上面的代码尾递归?

3 个答案:

答案 0 :(得分:6)

如上所述,它有点不确定。原因是,从技术上讲,该功能应该重新获得控制权,以便&&结果知道要返回什么。 (但这很容易被优化掉,大多数编译器可能会这样做。)

为了确保它的尾递归,只需避免对结果做任何事情而不是返回它。

int sum_n(int n, int *sum)
{
    if (!(n && (*sum += n))) return 0;
    return sum_n(n - 1, sum);
}

答案 1 :(得分:3)

我认为这个函数不是尾递归。

首先,我同意,以下形式是尾递归:

int sum_n(int n, int *sum)
{
    int tmp = n && (*sum += n);
    if (!tmp)
        return 0;
    else
        return sum_n(n - 1, sum);
}

但是上面的函数与原始函数完全相同。您提供的代码应与此相同:

int sum_n(int n, int *sum)
{
    int tmp = n && (*sum += n);
    if (!tmp)
        return 0;
    else
        return sum_n(n - 1, sum) ? 1 : 0;
}

区别在于,sum_n(n - 1, sum)的返回值无法直接用作函数的返回值:它应从int转换为_Bool

答案 2 :(得分:3)

不是在讨论尾递归的学术定义,但是,clang 3.3确实将sum()编译为循环,而不是递归。

        .file   "tail.c"
        .text
        .globl  sum
        .align  16, 0x90
        .type   sum,@function
sum:                                    # @sum
        .cfi_startproc
# BB#0:
        testl   %edi, %edi
        je      .LBB0_6
# BB#1:                                 # %.lr.ph
        movl    (%rsi), %eax
        .align  16, 0x90
.LBB0_3:                                # =>This Inner Loop Header: Depth=1
        addl    %edi, %eax
        je      .LBB0_4
# BB#2:                                 # %tailrecurse
                                        #   in Loop: Header=BB0_3 Depth=1
        decl    %edi
        jne     .LBB0_3
# BB#5:                                 # %tailrecurse._crit_edge
        movl    %eax, (%rsi)
.LBB0_6:
        xorl    %eax, %eax
        ret
.LBB0_4:                                # %split
        movl    $0, (%rsi)
        xorl    %eax, %eax
        ret
.Ltmp0:
        .size   sum, .Ltmp0-sum
        .cfi_endproc

        .section        ".note.GNU-stack","",@progbits

使用命令编译:

$ clang -c tail.c -S -O2

clang版本:

$ clang -v
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix