Problems of defining a factorial function in python - python

I'm recently starting to learn coding in Python, this is the code that I tried to define a function that helps me to find the factorial of a number. Yet, this chunk of code always returns me the double of its factorial.
def factorial(x):
empty = None
try:
adj_x = int(x)
except:
print("Invalid Input")
if adj_x < 0:
print("Invalid Input")
elif adj_x == 0:
print(0)
else:
l_adj_x = adj_x - 1 # if input == 4, this is 3
r = range(1, l_adj_x) # 1, 2, 3
for k in r:
n = adj_x - k # 4-1 = 3, 4-2 = 2, 4-3 = 1
if empty is None:
empty = n
else:
empty = empty * n
n_adj_x = adj_x * empty * n
print(n_adj_x)
I realized that it is the problem of the n in this line:
n_adj_x = adj_x * empty * n
Based on my own understanding, the last n in the for-loop should be 1 (I took 4 as an example of my input and stated all the possible outcomes of the loop in the comments next to each line of code) , if so, why does it appear to be the double of the correct answer (when I include n in n_adj_x = adj_x * empty * n) since the n should equal to 1?

If what you are trying to get is the factorial here are some
examples:
Example 1
n = 10
factorial = 1
for i in range(1,n+1):
factorial *= i
print(factorial)
Example 2 <-- worst option
Slowest option and requires the most additional memory.
def fact(x):
if x <= 1:
return 1
return x * fact(x - 1)
print(fact(10))
Example 3 <-- Best option
import math
print(math.factorial(10))
This is the python libs built in function and probably performs better than my simple loop, however I have not tested it.

Related

Reduce time /space complexity of simple loop

So basically if i have an iteration like this in python
Ive editted the question to include my full code
class Solution:
def myPow(self, x: float, n: int) -> float:
temp = [];
span = range(1,abs(n))
if n ==0:
return 1
if abs(n)==1:
temp.append(x)
else:
for y in span:
if y == 1:
temp = []
temp.append(x*x)
else:
temp.append(temp[-1] * x)
if(n < 0):
return 1/temp[-1]
else:
return temp[-1]
The problem link is : Pow(x,n)-leetcode
How can I modify this to conserve memory and time. Is there another data structure i can use. Im just learning python....
------------EDIT------------
ive modified the code to use a variable instead of a list for the temp data
class Solution:
def myPow(self, x: float, n: int) -> float:
span = range(1,abs(n))
if n ==0:
return 1
if abs(n)==1:
temp = x
else:
for y in span:
if y == 1:
temp = x*x
else:
temp = temp * x
if(n < 0):
return 1/temp
else:
return temp
I still have a problem with my time complexity.
Its working for many testcases, however when it trys to run with x = 0.00001 and n = 2147483647. The time limit issue arises
To reduce the time complexity you can divide the work each time by taking x to the power of 2 and dividing the exponent by two. This makes a logarithmic time algorithm since the exponent is halved at each step.
Consider the following examples:
10^8 = 10^(2*4) = (10^2)^4 = (10*10)^4
Now, there is one edge case. When the exponent is an odd number you can't integer divide it by 2. So in that case you need to multiply the results by the base one additional time.
The following is a direct recursive implementation of the above idea:
class Solution:
def myPow(self, x: float, n: int) -> float:
sign = -1 if n < 0 else 1
n = abs(n)
def helper(x, n):
if n == 1: return x
if n == 0: return 1
if n % 2 == 1:
return helper(x*x, n // 2) * x
else:
return helper(x*x, n // 2)
res = helper(x, n)
if sign == -1:
return 1/res
else:
return res
Note that we have taken abs of the exponent and stored the sign and deal with it at the end.
Instead of iterating from 1 to n, use divide-and-conquer: divide the exponent by 2 and use recursion to get that power, and then square that result. If n was odd, multiply one time more with x:
class Solution:
def myPow(self, x: float, n: int) -> float:
if n == 0:
return 1
if n == 1:
return x
if n < 0:
return self.myPow(1/x, -n)
temp = self.myPow(x, n // 2)
temp *= temp
if n % 2:
temp *= x
return temp
A simple naive solution might be:
def myPow(x: float, n: int) -> float:
## -----------------------
## if we have a negative n then invert x and take the absolute value of n
## -----------------------
if n < 0:
x = 1/x
n = -n
## -----------------------
retval = 1
for _ in range(n):
retval *= x
return retval
While this technically works, you will wait until the cows come home to get a result for:
x = 0.00001 and n = 2147483647
So we need to find a shortcut. Lets' consider 2^5. Our naïve method would calculate that as:
(((2 * 2) * 2) * 2) * 2 == 32
However, what might we observe about the problem if we group some stuff together in a different way:
(2 * 2) * (2 * 2) * 2 == 32
similarly:
((2 * 2) * (2 * 2) * 2) * ((2 * 2) * (2 * 2) * 2) == 32 * 32 = 1024
We might observe that we only technically need to calculate
(2 * 2) * (2 * 2) * 2 == 32
once and use it twice to get 2^10.
Similarly we only need to calcuate:
2 * 2 = 4
once and use it twice to get 2^5....
This suggests a recursion to me.
Let's modify our first attempt to use this divide and concur method.
def myPow2(x: float, n: int) -> float:
## -----------------------
## if we have a negative n then invert x and take the absolute value of n
## -----------------------
if n < 0:
x = 1/x
n = -n
## -----------------------
## -----------------------
## We only need to calculate approximately half the work and use it twice
## at any step.
## -----------------------
def _recurse(x, n):
if n == 0:
return 1
res = _recurse(x, n//2) # calculate it once
res = res * res # use it twice
return res * x if n % 2 else res # if n is odd, multiple by x one more time (see 2^5 above)
## -----------------------
return _recurse(x, n)
Now let's try:
print(myPow2(2.0, 0))
print(myPow2(2.0, 1))
print(myPow2(2.0, 5))
print(myPow2(2.1, 3))
print(myPow2(2.0, -2))
print(myPow2(0.00001, 2147483647))
That gives me:
1
2.0
32.0
9.261000000000001
0.25
0.0
If you have to loop, you have to lope and there is nothing that can be done. Loops in python are slow. That said you may not have to loop and if you do have to loop, it may be possible to push this loop to a highly optimised internal function. Tell us what you are trying to do (not how you think you have to do it, appending elements to a lis may or may not be needed). Always recall the two rules of program optimisation General Rule: Don't do it. Rule for experts: Don't do it yet. Make it work before you make it fast, who knows, it may be fast enough.

How do I input a list into a function and recieve a list in Python?

I am trying to make code that takes a list of numbers starting from a billion to 2 billion with an increment of 100 million and outputs a list of the number of steps it takes to reach one using the Collatz conjecture for each number.
My code:
from math import pow
# Defining the function
def collatz(the_input):
step = 1
while the_input > 1:
if (the_input % 2) == 0:
the_input = the_input / 2
else:
the_input = ((the_input * 3) + 1) / 2
step += 1
return step
the_inputs = []
the_number = pow(10, 9)
increment = pow(10, 8)
while the_number <= 2 * pow(10, 9):
the_inputs.append(the_number)
the_number += increment
print(the_inputs)
Loop through the list:
for num in the_inputs:
steps = collatz(num)
print(f"it takes {steps} steps for {num}")
This code uses f-strings.
Or, use a list comprehension for a list:
step_list = [collatz(num) for num in the_inputs)]
A version of your collatz function for lists:
def collatz_list(numbers):
result = []
for number in numbers:
step = 1
while number > 1:
if (number % 2) == 0:
number = number / 2
else:
number = ((number * 3) + 1) / 2
step += 1
result.append(step)
return result
Or you could just reuse your function like this:
result = [collatz(number) for number in the_inputs]
You can Create a list of all your input like :
inputs = [k for k in range(pow(10,9),2*pow(10,9),pow(10,8))]
And iterate for each element of your list:
outputs = []
for input in inputs :
outputs.append(collatz(input))
print(outputs)

How to write 2**n - 1 as a recursive function?

I need a function that takes n and returns 2n - 1 . It sounds simple enough, but the function has to be recursive. So far I have just 2n:
def required_steps(n):
if n == 0:
return 1
return 2 * req_steps(n-1)
The exercise states: "You can assume that the parameter n is always a positive integer and greater than 0"
2**n -1 is also 1+2+4+...+2n-1 which can made into a single recursive function (without the second one to subtract 1 from the power of 2).
Hint: 1+2*(1+2*(...))
Solution below, don't look if you want to try the hint first.
This works if n is guaranteed to be greater than zero (as was actually promised in the problem statement):
def required_steps(n):
if n == 1: # changed because we need one less going down
return 1
return 1 + 2 * required_steps(n-1)
A more robust version would handle zero and negative values too:
def required_steps(n):
if n < 0:
raise ValueError("n must be non-negative")
if n == 0:
return 0
return 1 + 2 * required_steps(n-1)
(Adding a check for non-integers is left as an exercise.)
To solve a problem with a recursive approach you would have to find out how you can define the function with a given input in terms of the same function with a different input. In this case, since f(n) = 2 * f(n - 1) + 1, you can do:
def required_steps(n):
return n and 2 * required_steps(n - 1) + 1
so that:
for i in range(5):
print(required_steps(i))
outputs:
0
1
3
7
15
You can extract the really recursive part to another function
def f(n):
return required_steps(n) - 1
Or you can set a flag and define just when to subtract
def required_steps(n, sub=True):
if n == 0: return 1
return 2 * required_steps(n-1, False) - sub
>>> print(required_steps(10))
1023
Using an additional parameter for the result, r -
def required_steps (n = 0, r = 1):
if n == 0:
return r - 1
else:
return required_steps(n - 1, r * 2)
for x in range(6):
print(f"f({x}) = {required_steps(x)}")
# f(0) = 0
# f(1) = 1
# f(2) = 3
# f(3) = 7
# f(4) = 15
# f(5) = 31
You can also write it using bitwise left shift, << -
def required_steps (n = 0, r = 1):
if n == 0:
return r - 1
else:
return required_steps(n - 1, r << 1)
The output is the same
Have a placeholder to remember original value of n and then for the very first step i.e. n == N, return 2^n-1
n = 10
# constant to hold initial value of n
N = n
def required_steps(n, N):
if n == 0:
return 1
elif n == N:
return 2 * required_steps(n-1, N) - 1
return 2 * required_steps(n-1, N)
required_steps(n, N)
One way to get the offset of "-1" is to apply it in the return from the first function call using an argument with a default value, then explicitly set the offset argument to zero during the recursive calls.
def required_steps(n, offset = -1):
if n == 0:
return 1
return offset + 2 * required_steps(n-1,0)
On top of all the awesome answers given earlier, below will show its implementation with inner functions.
def outer(n):
k=n
def p(n):
if n==1:
return 2
if n==k:
return 2*p(n-1)-1
return 2*p(n-1)
return p(n)
n=5
print(outer(n))
Basically, it is assigning a global value of n to k and recursing through it with appropriate comparisons.

Prime number calculator produces no output (python)

I am trying to find the 10001st prime using a basic logic:
1) Identify if a number is prime
2) Add it to a list if prime
3) Print the 10001st term in the list
Here is my code:
primelist=[]
import math
i=2
while True:
for x in range(2, int(math.sqrt(i))):
if i % x == 0:
continue
else:
primelist.append(i)
if len(primelist)== 10001:
break
print(primelist[-1])
Is the logic or code fundamentally wrong or inefficient?
What can I do to ameliorate/ make it work?
EDIT
I have incremented i (i+=1) and used all() to check if everything was indivisible, in response to comments
primelist=[2]
import math
i=3
while True:
for x in range(2, int(i**(1/2))):
if all(i%x!=0 for x in range(2, int(math.sqrt(i)))):
primelist.append(i)
i+=1
if len(primelist)== 10001:
break
print(primelist[-1])
Keep the algorithm/code structure the same (no optimization done), so we can easily share several language points, please see inline comments:
primelist=[]
import math
i=2
while True:
#changed to sqrt + 1, the second parameter of range is not inclusive,
#by adding 1, we make sure sqrt itself is included
for x in range(2, int(math.sqrt(i) + 1)):
if i % x == 0:
#you want break not continue, continue will try
#next possible factor, since you already figured out that this
#is not a prime, no need to keep trying
#continue
break
#a for/else block, many python users never encountered this python
#syntax. The else block is only triggered, if the for loop is naturally
#completed without running into the break statement
else:
#a little debugging, to visually confirm we generated all primes
print("adding {}".format(i))
primelist.append(i)
if len(primelist)== 11:
break
#advance to the next number, this is important,
#otherwise i will always be 2
i += 1
print(primelist[-1])
If you would like to optimize the algorithm, search online for "prime sieve".
This one should work if you want to stay with your algorithm:
import math
def is_prime(n):
for x in range(2, int(math.sqrt(n)) + 1):
if n % x == 0:
return False
return True
primelist = []
i = 2
while True:
if is_prime(i) is True:
primelist.append(i)
i += 1
if len(primelist) == 10001:
break
print(primelist[-1])
Here's a version of your code that's a bit faster, and which doesn't use much RAM. We really don't need to build a list of the primes we find. We don't use the numbers in that list to find more primes, and we're really only interested in its length. So instead of building a list we merely keep count of the primes we find.
# Include 2 in the count
count = 1
i = 3
while True:
if all(i % x for x in range(3, int(i ** 0.5) + 1, 2)):
count += 1
if count == 10001:
break
i += 2
print(i)
FWIW, here's a faster solution that uses sieving. We estimate the required size of the sieve using the prime number theorem. Wikipedia gives these bounds for p(n), the n'th prime number, which is valid for n >= 6:
log(n) + log(log(n)) - 1 < p(n) / n < log(n) + log(log(n))
We use the upper bound as the highest number in the sieve. For n < 6 we use a hard-coded list.
To save space, this sieve only holds odd numbers, so we treat the case of p(1) == 2 as a special case.
#!/usr/bin/env python3
''' Use a sieve of Eratosthenes to find nth prime
Written by PM 2Ring 2017.05.01
Sieve code derived from primes1 by Robert William Hanks
See http://stackoverflow.com/a/3035188/4014959
'''
from math import log
from sys import argv
def main():
num = int(argv[1]) if len(argv) > 1 else 10001
if num == 1:
# Handle 2 as a special case
print(1, 2)
return
elif num < 6:
# Use a pre-built table for (3, 5, 7, 11)
primes = [1, 1, 1, 1, 0, 1]
else:
# Compute upper bound from Prime number theorem
x = log(num)
hi = int(num * (x + log(x)))
print('upper bound', hi)
# Create a boolean list of odd primes in range(hi)
primes = [True] * (hi//2)
for i in range(3, 1 + int(hi**0.5), 2):
if primes[i//2]:
primes[i*i//2::i] = [False] * ((hi - i*i - 1) // (2*i) + 1)
# Count the primes until we get the nth one
k = 0
for i, b in enumerate(primes):
if b:
k += 1
if k == num:
break
print(num, 2*i+1)
if __name__ == "__main__":
main()
This code finds p(10001) = 104743 in under 0.15 seconds on my old single core 32 bit 2GHz machine running Python 3.6.0. It finds p(500000) = 7368787 in about 2.2 seconds.

Finding an approximation for 'e' using the first n + 1 terms of continued fraction in python

I have tried to follow the continued fraction example of [a1, a2, a3...] in wiki. When I run the program I am able to obtain result for n = 2 as 2.727272...75
but when I try n = 3 there are two outputs and they are lower (getting 2.394 and second line 2.3333...)
I am not sure whether I need to add another set to the y =... line. If so do I have to add another set of i -1+ so on to y each time I change n?
And why am I getting two lines of answer? Is it problem with how I have done the loop?
Here's my code:
n = abs(int(input("Enter number: ")))
y = 0
d = 0
for i in range(n, 1, -1):
if i == n:
y = (i - 1) + ((i - 1)/((i-1)/(i + (i/(i + 1))))
d = d + y
else:
d = i + 1
e = 2 + (1/d)
print (e)
From wikipedia's article on the subject,
This is what would feel appropriate (picking the n of your liking):
from __future__ import division, print_function
from sys import argv
from math import factorial
e = 0
n = int(argv[1]) if len(argv) > 1 else 100 # allowing to pass a value for n as an argument
for i in range(n):
e += 1 / factorial(i)
print(e)

Categories

Resources