5. Factorial - What's wrong with my formula?


#1

<>
def factorial(x):
total = 0
while x > 1:
total = total + (x * (x - 1))
x = x - 1
print total
else:
print x

print factorial(5)

Also, I'm trying to keep the editing proper in the Q&A, but I don't know HTML, and I can't figure out how to keep the indentation. What do I do for that?

</>


#2

I tried it a little differently, but it's also not working:

total = 0
def factorial(x):
while x > 1:
return total + (x * (x-1))
x = x - 1
else:
if x <= 1:
return x

print factorial(4)


#4
 import math

def factorial(x):
    return math.factorial(x)
factorial(4)

Um,,,, LEL this is the answer ha I dunno why that is so funny to me

.


#5

Fence the code with lines with three back-ticks:

```python
s = "Python syntax highlighting"
print s
```

s = "Python syntax highlighting"
print s

Code and Syntax Highlighting

Here is a code that would work if math.factorial() is not used:

def factorial(x):
    m = 1
    for n in range(x):
        m *= (n+1)
    return m

print factorial(4)

#6

Okay, a friend helped me see the errors. This works using the same logic I started with:

def factorial(x):
total = 1
while x > 1:
total = total * x
x = x - 1
return total

print factorial(1)


#7

Added comments for better understanding:

def factorial(x):
fac = 1 #initialize fac
while x > 1: #condition to ensure that if 1 is passed, it does not break the code
fac *= x #multiply each factor one by one and assign the result to fac
x = x - 1 #subtract 1 to avoid infinite loop
return fac #self explanatory

print factorial(5) #test by passing any number


#8

Here's how I solved this problem. Maybe it will help someone through this exercise. I know I was overthinking this one at first.


#9

here is mine, probably not as sophisticated though.

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

#10

this was the key for me that i kept messing up


#11

How in the world did you just call a function within itself?? You can do that??


#12

Why does this work? The function loops itself until it reaches 1?

I'm talking about the factorial (x - 1) part...


#13

Can you help this newbie: I was trying unsuccessfully to tweak my code when I came upon yours. My was simple (like yours), but I could not figure out why it was not working. Here's mine:

def factorial(x):
    int(x)
    num = 1
    for n in range(x):
        num = x * (x-1)
    return num

So I tried to understand your code-- When I did this to the second last line, m *= (x - 1) the code didn't work--neither did m *= (n+1)

Why?


#14

Visualize Python is a tool you can use to help you understand how the code works.

num = x * (x-1) will not give you the desired result because:

def factorial(x):           # x = 4
#   int(x) not needed
    num = 1
    for n in range(x):      # range(4) = [0, 1, 2, 3]
        num = x * (x-1)
    return num

#   num = 1
#   for 0 in [0, 1, 2, 3]:
#       num = x * (x-1) --> num = 4 * (4-1) --> num = 4 * 3 --> num = 12

#   num = 12
#   for 1 in [1, 2, 3]: 
#       num = x * (x-1) --> num = 4 * (4-1) --> num = 4 * 3 --> num = 12

#   num = 12
#   for 2 in [2, 3]:  
#       num = x * (x-1) --> num = 4 * (4-1) --> num = 4 * 3 --> num = 12

#   num = 12
#   for 3 in [3]:  
#       num = x * (x-1) --> num = 4 * (4-1) --> num = 4 * 3 --> num = 12
    return num              # return 12

print factorial(4)

Neither will m *= (x - 1) because:

def factorial(x):           # x = 4
#   int(x) not needed
    num = 1
    for n in range(x):      # range(4) = [0, 1, 2, 3]
        num *= (x - 1)      

#   num = 1
#   for 0 in [0, 1, 2, 3]:
#       num *= (x - 1) --> num = num * (x-1) --> num = 1 * (4-1) --> num = 1 * 3 --> num = 3

#   num = 3
#   for 1 in [1, 2, 3]: 
#       num *= (x - 1) --> num = num * (x-1) --> num = 3 * (4-1) --> num = 3 * 3 --> num = 9    

#   num = 9
#   for 2 in [2, 3]:  
#       num *= (x - 1) --> num = num * (x-1) --> num = 9 * (4-1) --> num = 9 * 3 --> num = 27

#   num = 27
#   for 3 in [3]:  
#       num *= (x - 1) --> num = num * (x-1) --> num = 27 * (4-1) --> num = 27 * 3 --> num = 81
    return num              # return 81

print factorial(4)

The first code returns 12 (4*3) and the second code returns 81 (3*3*3*3), when the desired result is 24 (1*2*3*4).

m *= (n+1) did not work for you because the variable in line 3 in your code is num = 1 and not m = 1 like in my code.

Below you can see why the code I put gives the desired result.

def factorial(x):           # x = 4
    m = 1
    for n in range(x):      # range(4) = [0, 1, 2, 3]
        m *= (n+1)
    return m

#   m = 1
#   for 0 in [0, 1, 2, 3]:
#       m *= (n+1) --> m = m * (n+1) --> m = 1 * (0+1) --> m = 1 * 1 --> m = 1

#   m = 1
#   for 1 in [1, 2, 3]:
#       m *= (n+1) --> m = m * (n+1) --> m = 1 * (1+1) --> m = 1 * 2 --> m = 2    

#   m = 2
#   for 2 in [2, 3]:
#       m *= (n+1) --> m = m * (n+1) --> m = 2 * (2+1) --> m = 2 * 3 --> m = 6

#   m = 6
#   for 3 in [3]:
#       m *= (n+1) --> m = m * (n+1) --> m = 6 * (3+1) --> m = 6 * 4 --> m = 24
    return m              # return 24

print factorial(4)

#15

Hope it helps!

def factorial(x):
sum=1
for i in range(1,x+1):
sum=sum*i
i=i+1
return sum

n=int(input('insert a number... '))
print factorial(n)


#16

It can become extremely CPU bound to do factorials in a sequential manner.

I created this function a while back to combat the fact that doing sequential multiplication to a given number can take an excessive amount of time.

My Factorial Code:

def factorial(number):
    """
    This function calculates the factorial of the given number.
    Numbers over 1000 can take over 10secs!
    :param number: Number to calculate
    :return: Returns the value of the number calculated
    """
    def shrink_list(lst):
        """
        This sub-function takes all the numbers in the factorial and multiplies
        every other even one to ever odd one. If the amount of numbers is odd
        it takes the last one off and adds it to the end after the multiplication.
        :param lst: List of numbers to multiply
        :return: Returns a list of numbers after shortening and multiplication.
        """
        if len(lst) % 2 == 0:
            return [(item1 * item2) for item1, item2 in zip(lst[0::2], lst[1::2])]
        else:
            new_lst = lst[:-1]
            new_lst = [(item1 * item2) for item1, item2 in zip(new_lst[0::2], new_lst[1::2])]
            new_lst.append(lst[-1])
            return new_lst

    # This creates a list of all the numbers that need to be factored
    numbers_to_multiply = [x for x in range(1, number + 1)]
    valid = False # For our flow control
    while not valid:
        # This will continually call the sub-function till the list
        # of numbers is less than 14.
        numbers_to_multiply = shrink_list(numbers_to_multiply)
        if len(numbers_to_multiply) < 14:
            valid = True
    return_value = 1
    # This for loop finishes the multiplication on the remaining members.
    for number in numbers_to_multiply:
        return_value *= number
    return return_value

While smaller numbers are computed in roughly the same amount of time once you reach around 1250 my function start to dramatically beat the sequential method.

Your basic Factorial method,

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

When you time the basic vs my factorial function you get some huge differneces as the numbers climb.

# All times are from cProfile
@10000
Basic: 0.065 secs
Mine: 0.029 secs

@100000 
Basic: 15.535 secs
Mine: 1.885 secs

@1000000
Basic: Over 5 mins
Mine: 89.248 secs

You can play with ether on this Lab link, on the lab site because it is using 2.7.* instead of 3.* list comprehension is slower because it was improved in 3.*.

My function still beats out the basic function start around ~3500 but up till that point the basic function works better on the lab site. You will notice much improved times on your personal IDE and if you use 3.*.

Also some of the builtin functions were improved in the newer version of 2.7.* so it should run better in the newer version. The lab is 2.7.2. I should also note that using time to time the function is not very accurate.

As always best of luck, if you have any questions ask freely.


#17

def factorial(x):
sol = 1
for i in range(1,x+1):
sol *= i
return sol


#18

What are some common calculations for big numbers that are usually thrown in game programming that will require optimization such as this?

I'm guessing that game heavy with physic calculations will frequently run into conditions where the number crunching simply takes so long that the update will run ahead of the calculations.