Question

I know this title is duplicated with Is this tail-recursion?, but this is different and I could not get a clue from the previous question. so I have to ask again.

The code:

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

It is said(foreign language source) that, tail recursion have two features:

  1. The function is self-called
  2. Only constant stack space is needed

So are these two features the only key factors for judging tail recursion? And whether the logical operator && in return statement affects tail recursion or not?

Most of all, is the above code tail recursion?

Was it helpful?

Solution

As written, it's a bit iffy. Reason being, technically, the function should regain control in order to && the result to know what to return. (This is easily optimized away, though, and most compilers will probably do so.)

In order to make sure it's tail-recursive, simply avoid doing anything with the result other than returning it.

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

OTHER TIPS

This very function, I think, is not a tail recursion.

First, I agree that, this following form is tail recursion:

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

However the above function is not literally equivalent to your original one. The code you provide shall be equivalent to this:

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;
}

The difference, is the return value of sum_n(n - 1, sum) could not be used directly as the return value of your function: it shall be casted from int to _Bool.

Not talking about the academic definition of tail recursion, however, clang 3.3 does compile sum() as a loop, not recursion.

        .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

compiled with command:

$ clang -c tail.c -S -O2

clang version:

$ clang -v
clang version 3.3 (tags/RELEASE_33/final)
Target: x86_64-unknown-linux-gnu
Thread model: posix
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top