5/15 My custom factorial function requires an integer input... Why?


#1

I wrote out a factorial function the hard way (rather than calling the "factorial" function in Python), and it worked fine. I added a bit to call for raw_input from the user and print the result.
It didn't work until I added the int(user_input) operation when calling the function...
Why does the function require the input to be an integer? Is there a better way specify the raw_input variable type as an int (or any other type)? Thx!

def factorial(x):
    result = 1
    while x > 0:
        result *= x
        x -= 1
    print result
    return result

user_input = raw_input("Enter a number: ")
factorial(int(user_input))

Factorial
5. Factorial, code not working :(
#2

Hi @dfarrit,

The reason you have to use int() is because raw_input() will return a unicode string and python will not do arithmetics with strings (apples) and integers (oranges)

There are many ways to do input validation and you could probably whip up a separate function to do just that and that spits out error messages and log errors to file and such but for your exemple here what you did is fine. If you must change something to ease your mind, you could just use int() inside your function instead of within the function call:

def factorial(x):
    result = 1
    y = int(x)
    while y > 0:
        result *= y
        y -= 1
    print result
    return result

user_input = raw_input("Enter a number: ")
factorial(user_input)

#3

@dfarrit Below I have implement a sample test where entering a non-integer(string) will not crash the program because it is handled

def factorial(x):
    fact = 1
    try:
        x = int(x)
        while(x>0):
            fact *= x
            x-=1
        return fact
    except ValueError:
        return ("Invalid Input")
        
    

print("Hit 'x' to terminate")
while True:
    user_value = raw_input("Enter a Value: ")
    if user_value == "x":
        break   
    print factorial(user_value)

You can also visit this playground here to test it out

Click here to visit playground


#4

Thank you @rydan , that's a very good exemple. Couldn't ask for more, really!


#5

@denisaltroy Yeah I usually turn to exceptional programming when it comes to handling user inputs


#6

I like what you did here @rydan, the only issue is I like to break things... So I tried to get it to factor a number over 150 (on the lab site) and it freezes so me being me I was like how can we get it to factor any number.

The below will do it by breaking down all then numbers and multiplying them together then return a list of approximately 1/2 the size, it keeps doing this till the list sizes are under 14. I time tested mine vs yours.

On anything smaller than 1000 we are matched almost neck in neck with you taking the lead mostly over that though my code starts to break through quickly.

It was a fun little project, thanks for giving me something to do for a bit! There are several different ways to do this but this one was the fastest to do. You should try some of the other ways. Again thank you!

My Code on my machine:
100592 function calls in 8.406 seconds @ 2750 Count 10,311 kb file

Your Code on my machine:
13759 function calls in 10.284 seconds @2750 Count 10,311 kb file

As you can clearly see I do roughly 9x the function calls in almost a whole 2 secs less time. It get's more sever the large the number.

Again,

Mine:
132795 function calls in 17.598 seconds @3500 Count 17,323 kb file
Yours:
17509 function calls in 21.418 seconds @3500 Count 17,323 kb file

Again:
Mine:
179307 function calls in 37.331 seconds @4500 Count 29,708 kb file
Yours:
22509 function calls in 46.765 seconds @4500 Count 29,708 kb file

MY CODE:

import cProfile

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


def cf_range(num_range):
    """
    This function saves the factorial to file. It also calls the function
     ranging from 1 to the given number. So all factorials to the number are
     saved to file. The computer has problems displaying any number
     the system can not handle.
    :param num_range: Range of numbers to be factored
    """
    with open("factorial_of_%s.txt" % str(num_range), "w+") as file:
        for number in range(1, num_range + 1):
            file.write(str(factorial(number)) + "\n")

cProfile.run("cf_range(5000)")

Your Code:

import cProfile

def factorial(x):
    fact = 1
    try:
        x = int(x)
        while(x>0):
            fact *= x
            x-=1
        return fact
    except ValueError:
        return ("Invalid Input")


def cf_range(num_range):
    with open("other_factorial_of_%s.txt" % str(num_range), "w+") as file:
        for number in range(1, num_range + 1):
            file.write(str(factorial(number)) + "\n")

cProfile.run("cf_range(2750)")

5. Factorial, code not working :(
#7

@zeziba that's a very good analysis and detailed analysis. That's great thanks


#8

Very good work indeed @zeziba , I'd love to see a version with descriptive comments sprinkled all around to help novice users bridging the gap! :smile:


#9

I came up with this:

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

The point is to make from x (for example x = 3) list starting with largest number, without 0.
So to get rid of zeroes, range(1,x + 1) and then to reverse it we can use python built in function reversed.

Then do n * n * n...


#10

@denisaltroy

I have added some comments to the code for you!
:smile:

@methodplayer70564

Your function came in at

22509 function calls in 45.656 seconds @4500 Count

Your Code:

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

#11

Thanks @zeziba! :smile:
On my behalf and on behalf of anyone who will benefit from them! :v:


#12

I did it without "reversed" because there is no reason for that. If you multiply 3*2*1 or 1*2*3 the result will be the same. A little mathematics for us :blush:
def factorial(x):
d=1
for c in range(1,x+1):
d*=c
return d