C++ Programmer Defined Factorial Function

Click For Summary

Discussion Overview

The discussion revolves around understanding a recursive factorial function implemented in C++. Participants explore the logic behind recursion, the mechanics of function calls, and the performance implications of using recursion versus iteration.

Discussion Character

  • Exploratory
  • Technical explanation
  • Debate/contested
  • Mathematical reasoning

Main Points Raised

  • One participant seeks clarification on the logic of the recursive factorial function and how the return statement operates within it.
  • Another participant suggests that recursion is not specific to C++ and compares it to calling different functions, questioning the understanding of "returning" values.
  • Some participants express uncertainty about the mechanics of recursion and the implications of returning values to function calls.
  • There is a discussion on the performance of recursive functions versus iterative solutions, with one participant noting significant time differences in execution for large iterations.
  • Concerns are raised about the efficiency of recursion, with some participants suggesting that it may carry performance penalties due to stack space consumption and function call overhead.
  • Others argue that recursion can be acceptable in certain contexts, such as in Lisp, and emphasize the importance of understanding both recursion and iteration.
  • One participant provides empirical timing results comparing iterative and recursive implementations of the factorial function, highlighting the performance disparity.
  • Another participant questions the optimization capabilities of compilers regarding recursion, noting that their compiler did not convert a recursive function into a loop.

Areas of Agreement / Disagreement

Participants express a mix of agreement and disagreement regarding the efficiency and appropriateness of recursion. While some acknowledge the performance drawbacks, others defend its use in certain programming contexts. The discussion remains unresolved on the best practices for using recursion versus iteration.

Contextual Notes

Participants mention various factors affecting performance, such as compiler optimizations and the nature of the recursive function (e.g., whether it is tail recursive). There are also references to specific compiler settings and architectures that may influence timing results.

Who May Find This Useful

This discussion may be useful for C++ programmers, particularly those interested in understanding recursion, performance implications of different programming approaches, and the nuances of function calls in programming.

Saladsamurai
Messages
3,009
Reaction score
7
Hi

I am relatively new to C++ and I am having a little trouble understanding, in detail, the logic
of this recursive function.

Can someone tell me if my reasoning this out is correct?

Code:
int fact (int n)
{
	if (n==1)
	return 1;
	 
	else
	return (n*fact(n-1));
	
}
So if the user enters 1, it returns 1. But if the user enters 3... what happens here?

it returns 3*fact(2)
and then fact(2) returns 2*fact(1)
and fact (1)=1
so we have 3*2*1= 3!

okay...so I guess I do get it kind of.

But when it says "return (n*fact(n-1)" where exactly is it "returning" it?

It seems like it means "return it to the argument of the function".

Is that more or less correct? Especially what is in boldface...
 
Technology news on Phys.org
It's a http://en.wikipedia.org/wiki/Recursion#Recursion_in_computer_science". Not C++ specific thing.

I understood it by assuming that
"int fact (int n)" is not equal to "fact(n-1)" i.e. they are two different functions something like

int fact1 (int n)
{
return fact2(n-1);
}

int fact2 (int n)
{
return something;
}To function or method, there is no difference between calling itself or calling another function..I would say in that line it just calling itself and places the call on the stack.
In 3 case, it keeps on putting calls on the stack until you return 1:
func(1) = 1
func(2)
func(3)

func(1) is evaluated which was called by func(2) and is removed from the stack, then func(2) and then func(3)
 
Last edited by a moderator:
It's a recursive function. Not C++ specific thing.

Agreed.

I understood it by assuming that
"int fact (int n)" is not equal to "fact(n-1)" i.e. they are two different functions something like

int fact1 (int n)
{
return fact2(n-1);
}

int fact2 (int n)
{
return something;
}

Not sure about all of that. I think the way I wrote it makes more sense..but that's me!


I guess I just need to know this
when it says "return (n*fact(n-1)" where exactly is it "returning" it?

Is it returning it to n?
 
noticed your edit. I think that makes some sense to me.
 
when it says "return (n*fact(n-1)" where exactly is it "returning" it?

Is it returning it to n?

You might want to use some better word than returning to n. I don't understand "what "returning to n" is. return (n*fact(n-1)) is just equivalent to return (a constant * fact (n-1))
Whenever fact (n-1) is evaluated and removed from the stack, it returns another constant which is multiplied then by n and then function returns the result.

I don't know anything more about recursion - just that I need a base case (stopping condition) and other body. You can use it instead of for/while loops (in some cases) if your code looks neater but in my understanding, use recursion only if it make your code look simple.
 
Saladsamurai said:
it returns 3*fact(2)
and then fact(2) returns 2*fact(1)
and fact (1)=1
so we have 3*2*1= 3!
Not quite, the return statement is the value returned when that instance of the function exits. The first return statement, return(3*fact(2)) requires that fact(2) return a value before the expression 3*fact(2) can be evaulated and returned from that instance of the function.The next nested instance of the function has a return statement, return(2*fact(1), and requires fact(1) return a value before it can evaluate the expression and return that value ...

So this sequence unfolded is:

Code:
     i = fact(3)
         call fact(2)
               call fact(1)
                   fact(1) returns a 1
               fact(2) returns (2*1)
         fact3 returns(3*2)
     i = 6
 
Saladsamurai said:
where exactly is it "returning" it?
To the place where the function is called.

If x is an expression of type int, then fact(x) is also an expression of type int. The value of fact(x) is the value that was returned.

e.g., if the expression x has the value 7, then the value of fact(x) is the value of the expression 7 * fact(6).
 
Okay.
So fact (3) tries to return an int value. But since it is returning 3*(fact(2))
fact (2) to has to be evaluated first... and so on.
 
rootX said:
but in my understanding, use recursion only if it make your code look simple.
I was under the impression that recursion carries serious performance penalties, so one should avoid it whenever possible even at the expense of code clarity. Perhaps outside of scientific computing this would be less of an issue, and I'm fairly sure that if you're using something like Lisp, recursive functions are perfectly acceptable.
 
  • #10
"I'm fairly sure that if you're using something like Lisp, recursive functions are perfectly acceptable."

I would hope so.

Recursion is perfectly fine, and don't let anybody tell you differently. Yes, it isn't as efficient as looping. This is, of course, an immediate consequence of the underlying hardware's implementation. It needn't have been such, and may not always be.

Next, it is always possible to make a recursive function iterative, and vice versa. You never "need" to use recursion.

You really should know how both recursion and iteration work.
 
  • #11
arboretum said:
I was under the impression that recursion carries serious performance penalties
It comsumes stack space, but with GB's of memory and a large stack size specified, it shouldn't be an issue.
 
  • #12
For quick functions, I believe the main problem with recursion is that it can't be inlined -- the computer spends more time doing the setup/cleanup for function calls than it does actually performing the calculation, and there is no opportunity for reusing registers or extracting constant subexpressions. There might even be an additional penalty when it gets the branch prediction wrong on the final iteration.

Of course, a good compiler will automatically convert some forms of recursion into loops. :smile:
 
  • #13
arboretum said:
I was under the impression that recursion carries serious performance penalties, so one should avoid it whenever possible even at the expense of code clarity. Perhaps outside of scientific computing this would be less of an issue, and I'm fairly sure that if you're using something like Lisp, recursive functions are perfectly acceptable.

Depends what's important to you..

- performance
- readability
 
  • #14
Alright, fine.

Implemented both in C++.
Running each 100,000,000 times for integers 0-9. Integer function.
Timing them, in seconds.

Iterative solution:
45 seconds.

Recursive solution:
168 seconds.

I'm actually sort of impressed by the difference. Here's the code I used:


int factorial_it(int n)
{
int result = 1;

for(int i = 2; i <= n; i++)
result *= i;

return result;
}

int factorial_rc(int n)
{
return (n <= 1 ? 1 : n * factorial_rc(n-1));
}

int main()
{

int t1, t2;

t1 = (int)time(NULL);
for(int n = 0; n < 100000000; n++)
{
for(int i = 0; i < 10; i++)
{
//int tmp = factorial_it(i);
int tmp = factorial_rc(i);
}
}
t2 = (int)time(NULL);

count << "Elapsed time: " << t2-t1 << endl;


return 0;
}
 
  • #15
What compiler / optimization settings? (/ architecture)

I tried your code using MSVC++ 2008, both under DEBUG and RELEASE builds, and my results were:

DEBUG: 50 and 158 (similar to what you got)
RELEASE: 7 and 15


I'm somewhat dissapointed that MSVC++ didn't turn the recursive function into a loop. Maybe compilers don't do that optimization, despite what I had learned?
 
  • #16
Well, strictly speaking, the way I wrote the factorial_rc function, it's not tail recursive. That's sort of the point... I believe you'll agree the multiplication, not the recursive call, is the "last" operation being done. I don't think compilers are written to do this optimization since, well, where would you stop it?

I used the V.S. c++ thing at some sort of dingy lab I happened to be at when I did it. I didn't specify any compiler settings, and I was running under debug (almost certainly). As you can probably tell, I wasn't being too careful about it.
 

Similar threads

  • · Replies 6 ·
Replies
6
Views
12K
  • · Replies 64 ·
3
Replies
64
Views
8K
  • · Replies 5 ·
Replies
5
Views
3K
  • · Replies 39 ·
2
Replies
39
Views
5K
  • · Replies 9 ·
Replies
9
Views
2K
  • · Replies 36 ·
2
Replies
36
Views
6K
  • · Replies 17 ·
Replies
17
Views
2K
  • · Replies 2 ·
Replies
2
Views
3K
  • · Replies 5 ·
Replies
5
Views
3K
  • · Replies 1 ·
Replies
1
Views
2K