Factorial function? what?

Literally just copy pasta-ed their solution. I’ve spent over an hour reading this and other threads and not only do I not have a clue what the purpose of creating a duplicate function is, that response may as well have been in Greek for all the sense it made.

I generally make it a policy not to copy code directly, but this exercise was just ridiculous, IMHO.

Hi @historic66, I cqn totally relate to your frustration hahaha, so let me try explaining more in depth later on when I have more time to spare yeah? there is actually meaning to this exercise :slight_smile:

I would LOVE an explanation because, in my eyes at least, it seems like this is teaching new programmers bad habits by (seemingly, at least) going against Python’s “Don’t Repeat Yourself” motto due to writing a function to call a built-in one.

Hi @historic66,

sorry for the late reply, I was a tad bit busy yesterday :stuck_out_tongue:

Let us first look at an example of the solution which this exercise is supposed to lead us to produce:

def factorial(x):
    return 1 if x < 2 else x * factorial(x-1)
print factorial(10)

You face the same problem as me in that we both thought that our code (such as the one written above) is utilising the in-built Python factorial function, and is hence a bogus exercise. Upon trawling through multiple threads, I realised that this is in fact not the case.

What this exercise aims for us to do is not to utilise the in-built factorial function, but rather, to understand how the calculation of factorial(n) works and then create a function to do this calculation. Although there is indeed already an in-built Python function that can be used for this purpose, forcing us to think of our own function using our knowledge of factorial is a far better way to train us as new programmers. Upon such noble intentions was the Python exercise in question established.

Let us then inspect why the proposed solution is not simply calling a built-in factorial function, but rather constructing a function that calculates factorials.

In the body of the function, we have this line:

return 1 if x < 2 else x * factorial(x-1)

What is happening here? As the moderator @ mtf so eloquently puts it, we effectively “build a return stack and solve the recursion by dumping the stack when a base case is reached”. What does this really mean? Again, I refer back to his teachings:

"The way a recursion works is by building a stack of return values. Let’s say we ask for factorial(5). x is 5 when we start the function. The recursion takes place when x is multiplied by the factorial of 1 less than x. Each return value is stored in a stack. A value times a return value. When the base case is reached, 1 is returned. Then we go back through the stack.

[[[[[1] * 2] * 3] * 4] * 5]
     1! == 1
        2! == 2
             3! == 6
                  4! == 24
                       5! == 120

in reverse order. Each block is a return value. Bear in mind that without the base case, we might never get out of a recursive loop, hence the fatal runtime error when it runs out of registers in the stack."

Take a few moments to really understand what he was trying to get at (I did, when I first saw that post). In simpler, layman terms, whenever we are trying to find the factorial of a number, such as factorial(5), the suggested solution will cause result in 5 * factorial(4), and because we called the function factorial in this line, the function will rerun, but with factorial(4) this time to get 4 * factorial(3), and so on and so forth until x < 2, in which case 1 is directly returned, terminating this loop (recursion). After all the reruns of our function, the final calculation will become 5 * 4 * 3 * 2 * 1 or otherwise known as 5 * factorial(4) in the first run, 5 * 4 * factorial(3) by the second run, 5 * 4 * 3 * factorial(2) by the third run etc.

If it helps, I suggest that you try this exercise by pretending that you do not know an in-built Python factorial function exists (I did). How can you build a function that calculates factorial then?

Better still, try the exercise again by naming the function a different name (any function name minus the taboo ones will work). Let me give you an example:

def my_own_function(x):
    return 1 if x < 2 else x * my_own_function(x-1)

You will realise that this function works perfectly well as well, simply because this exercise was never about calling the in-built factorial function.

Hope this helps you :slight_smile: I had quite a headache over this some time back as well hahah

4 Likes

My strategy on this program is missing one key component. For some reason I cannot find a way to get one single list of these three numbers. The 12 overrides the 30 and the 2 overrides the 12. If I can get them into one list, I can multiply them together, but for now it seems I am stuck. Any suggestions on how to make this method work?? Thanks in advance!

1 Like

Hi @blogmaster25120,

I like how you actually bother to think of another approach to solve this problem :slight_smile: Even if it may not be the most elegant or simplest solution, it is mathematically sound :slight_smile:

I have some suggestions for you to improve your code:

1… placement of your numbers list

You placed your list within your while statement. What this will result in is that every time the while statement is run, the numbers list becomes a blank list all over again, resulting in you getting the situation which you described.

Where do you think the list could be shifted to instead? :slight_smile:

2… the point of having the line q -= 1

What is the point of doing this? Is there a point to it in the first place?

3… how to get the final answer

Given that you resolve the issue in point 1, you will realise that you are still not able to get the right answer. This is because you are missing an integral part of the solution; by what you have currently, the most you can get is a list containing 3 numbers, like so: [30, 12, 2]. What else should be added in order for the function to calculate the multiple of the elements in the list?

Let me know how things go :slight_smile: All the best!

Thank you for the help! I moved the list which solved a big problem and took away the q -= 1 because I realized it was completely redundant! Now I am at a point where my only error is the code saying that my solution is not correct because it is returning [2] and not 2. I am not sure how to make a fix that won’t screw up the code for all the other numbers! If there is an easier way to calculate all the intergers in a list added together that would be much appreciated!

Hi @blogmaster25120,

Good job on editing based on the suggestions in the previous post :slight_smile:

So, for the next bit:

1… the location of total

Your first mention of the variable total appears in the first function (a.k.a. the factorial function). However, when is it that you truly have need for this variable? If it isn’t where it has been, where should it be instead?

2… the problem of a function calling another function

In your code, you created two different functions, factorial and multiply. However, the exercise requires that you ultimately call only 1 function for your calculations, like so:

print factorial(5)

if you are trying to find 5!. Yet if you do so using your code, what will happen is that only one of the functions will be executed, and this function is the factorial function. Hence, when you plugged in print factorial(2), the answer is [2], because only the first factorial function was executed.

Hence, I want to invite you to think about how to solve this problem. Here are some guiding clues for you:

  • Which function should be called within which function?
  • How can you do this calling?

If you’re still stuck, let me know and I’ll see if I can help further :slight_smile:

On another note, going by the same approach, I also thought of doing this:

 def factorial(x):
    numbers = []
    total = 1
    if x == 1:
        return 1
    while x  > 1:
        q = x - 1
        num = x * q
        numbers.append(num)
        x -= 2
    for no in numbers:
        total *= no
    return total


print factorial(5)

which is admittedly a bit of a cheat because I didn’t create a new function to reflect my thought process (I think they call it abstraction?). But I didn’t want to show how to call the functions just yet :stuck_out_tongue: So yup, iterating through the elements in the numbers list instead of using the index approach works too.

Good luck :slight_smile:

I guess I understand the purpose, but I’m starting the realize the author of this section has a real hard-on for writing custom functions to replace existing ones. While I agree that teaching us to think this way has its benefits, I cannot stand when programming tutorials have us “re-invent the wheel”.

That’s actually a fair question ! Why can’t factorial(x) work as simple as sum(x) (built-in function) right ?

Simply 'coz founder of Python didn’t make it that way I guess … that person wanted to make it a bit trickier for us students …

I’ve got headache just reading it lol.

2 Likes

I unfortunately have no idea where total should go without getting an error or how these functions call themselves. I have been playing around for 3 hours with this code it just does not seem to work.
Is there something else wrong with the code?

Why can’t you just use a simple iterative method:

def factorial(x):
    total = 1
    for num in range(1, x+1):
        total *= num
    return total

Basically, it counts up to x and multiplies all the numbers together to get the total–covers cases 1 and 0 as well since I think 0! = 1. Doesn’t this work?

2 Likes

short and simple way
def factorial(x):
c=1
fact=1
while c<=x:
fact=fact*c
c = c+1
return fact

The most simple and correct way I think (for positive integers):

def factorial (x):
    if x >0:
        return x*factorial(x - 1)
    else:
        return 1

def factorial(x):

if x == 1:
    return 1
    
return x*factorial(x-1)

x = 4
print factorial(x)

This is my code,I think it easy enough.Is any easy way ?

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.