For the factorial exercise, I created two versions of the solution.

My first thought was to break everything down into chunks - e.g. how would I build this in excel? Once I figured that out, I looked for ways to simplify this.

You can use much larger numbers, but expect to wait for a while.

Would be interested to learn more about performance testing for sure...

**VERSION 1**

```
def factorial(x):
x = abs(x) # accomodate negative numbers
factor_list = [] # blank list
factor_calc = 1 # prevent hitting 0, which results in final value of 0
for i in range(1, x+1): # from each number in 1 to x (including x)
factor_list.append(i) # append this number to the list, factor_list
for i in factor_list: # within each number in the list, factor_list
factor_calc = i * factor_calc # take current value of the number in the loop and multiply by previous total
return (factor_calc)
# print(factorial(55221))
import cProfile # this imports the performance testing library
cProfile.run('factorial(55221)') # this outputs the performance metrics of the function
```

This outputs:

```
55226 function calls in 0.963 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.963 0.963 <string>:1(<module>)
1 0.958 0.958 0.963 0.963 test_one.py:1(factorial)
1 0.000 0.000 0.000 0.000 {built-in method builtins.abs}
1 0.000 0.000 0.963 0.963 {built-in method builtins.exec}
55221 0.004 0.000 0.004 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
[Finished in 1.0s]
```

# **VERSION 2

the seemingly more efficient solution**

```
def factorial_b(x):
x = abs(x) # accomodate for negative numbers
calc = 1 # prevent multiply by 0, which results in final value of 0
for i in range(1, x+1): # from each number in 1 to x (including x)
calc = calc * i # calc = current calc value * current value of i in range
return calc
# print (factorial_b(55221)) # uncomment this to see the function's output
import cProfile # this imports the performance testing library
cProfile.run('factorial_b(55221)') # this outputs the performance metrics of the function
```

This outputs:

```
5 function calls in 0.847 seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.847 0.847 <string>:1(<module>)
1 0.847 0.847 0.847 0.847 test_two.py:1(factorial_b)
1 0.000 0.000 0.000 0.000 {built-in method builtins.abs}
1 0.000 0.000 0.847 0.847 {built-in method builtins.exec}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
[Finished in 0.9s]
```