tags:

views:

318

answers:

5
int fact_rec(int n)
{
    printf("%d\n",n);
    if(n==1) return n;
    else return fact_rec(--n)*n;
    //else return n*fact_rec(--n); gives same result
    //correct output comes for n*fact(n-1)
}

In the above recursive implementation of the factorial function, fact_rec(5) returns 24. Whereas, if I use n*fact_rec(n-1) in place of n*fact_rec(--n) the output is correct : 120. Also, it doesn't matter whether I use n*fact_rec(--n) or fact_rec(--n)*n. Shouldn't it matter if I use n*fact_rec(--n) or fact_rec(--n)*n?

And shouldn't the output have been 120 in all the cases?

A: 

--n in your function really means:

int fact_rec(int n) {
    printf("%d\n",n);

    if(n==1) {
         return n; 
    } else {
        n = n - 1; /* <---- effect of --n */
        return fact_rec(n)*n;
    }
}
dfa
Replace "really means" by "is being interpreted by the compiler you're using as" and you'd be right.
NVRAM
A: 

The problem is here:

else return fact_rec(--n)*n;

you're decrementing n before the multipliation

so if n starts as 5 it runs as

return fact_rec(4)*4;

Edit: Down voted for a correct answer to the question? I don't get it.

Graphics Noob
What you say is an accurate description of what appears to have happened on his compiler, with his compiler options, on this occasion, etc. I assume the downvote is because you didn't mention the rather more important fact that no particular behaviour can be relied upon for this code.
Steve Jessop
+4  A: 

Your confusion seems to be about the order - unlike the other answers, I am assuming you already know what --n does...

The compiler knows it needs the value of fact_rec(--n) before it can evaluate fact_rec(--n)*n whichever way round you write it, so the function is evaluated first, and the value of n multipled has always already been decremented.

David M
There's no guarantee of that in C. The expression "n" may be evaluated first. In Java, subexpressions are evaluated left-to-right; in C, it's implementation-defined.
Rob Kennedy
Looks like qrdl's answer below is best then!
David M
@Rob - pedantically speaking, it not even implementation defined - it's unspecified. Implementation defined means the implementation must document what it does, and that's not required for order of evaluation of sub-epressions.
Michael Burr
+18  A: 
return fact_rec(--n)*n

is dangerous. The order of argument evaluation is undefined in C (except for &&, ||, comma and ternary operators) so value for second occurrence of n could vary.

The rule of thumb: never use variable you are incrementing/decrementing twice in one expression.

qrdl
And comma operator.
Steve Jessop
@onebyone Thank you, corrected.
qrdl
Leaving the order undefined gives the compiler the greatest latitude in code generation and optimization. You might see different results depending on your optimization settings.
Mark Ransom
And I've a sneaking suspicion that it's not just that order is undefined, but behaviour. 5(4) says "Between the previous and next sequence points a scalar object shall have its stored value modified at most once... the prior value shall be accessed only to determine the value to be stored. The requirements of this paragraph shall be met for each allowable ordering of the subexpressions of a full expression; otherwise the behavior is undefined". So if I read correctly, in the allowable ordering "n; --n; fact_rec; *" this violates 'accessing the prior value' of n.
Steve Jessop
I'd extend the rule of thumb to include any function call with side-effects.
NVRAM
And the ternary operator ?: has a sequence point at the ?. I've found the list of sequence points, it's right near the start of the standard, 1.9 (16-19). As far as I know, it's exhaustive. Btw, my quotes are from the C++ standard, and I've just noticed that the question says C. Sorry about that, and I don't have the C standard to hand, but I'm pretty sure that C++ wouldn't make something like this undefined if it was defined in C.
Steve Jessop
sheepsimulator
Michael Burr
A: 

There is actually no need to modify n at all. return n * fact_rec(n - 1) takes care of it and is the right way to do it.

sigjuice