I am learning this Exponentiation Recursive algorithm, it works well.
But I don't understand why this works?
Because I expect that always returns 1,1,1...if n is even because a doesn't multiply in the return.
When I try recPower(3,2), and print the factor step by step, it will be like:
1
3
9
But, why does 3 come out?
def recPower(a, n):
# raises a to the int power n
if n == 0:
return 1
else:
factor = recPower(a, n//2)
if n%2 == 0: # n is even
return factor * factor
else: # n is odd
return factor * factor * a
Just follow it step by step:
recPower(3, 2)
n != 0 so go down the else branch:
factor = recPower(3, 2//2)
Which is:
recPower(3, 1)
In this recursive step n != 0 we follow the first else branches, 1%2 != 0 so we follow the second else branch. The factor is therefore 1 and a == 3.
The return value of this step is therefore:
factor * factor * a
or
1 * 1 * 3
Related
I tried to write my own power() function in python but when i compared it with python inbuilt pow() function in output and speed. I found that my code is 6-7 times slower and last 3-4 digits of output is different as compared to output of inbuilt pow() function for floating point numbers. I am totally new to python and unable to find the explanation. plz help
Note:- I have used binomial expansion for calculating fractional power and Binary Exponent for integral power
Here is my code-
def power(x, n):
if not(isinstance(x, complex) or isinstance(n, complex)):
res = 1
if n == 0 and x != 0:
return 1
if n > 0 and x == 0:
return 0
if n < 0 and x == 0:
return "Zero Division Error"
if n == 0 and x == 0:
return "Indeterminate Form"
if n == 1:
return x
if n > 0 and n < 1:
return fpower(x,n)
if n > 1 and n < 2:
return x*fpower(x,n-1)
if n == -1:
return 1/x
if n < 0 and n > -1:
return fpower(x,n)
if n < -1 and n > -2:
return 1/x*fpower(x,n+1)
if n >= 2:
f_p = n - n // 1
t_x = x
n //= 1
if n%2:
res = x
n //= 2
else:
res = 1
n //= 2
while n != 1 and n > 1:
if n%2:
res *= x*x
x *= x
n //= 2
res *= x*x
if f_p == 0:
return res
elif f_p < 1:
return res*fpower(t_x,f_p)
if n <= -2:
f_p = n+(-n // 1)
t_x = x
n = -n // 1
if n%2:
res = 1/x
n = n // 2
else:
res = 1
n = n // 2
while n != 1 and n > 1:
if n%2:
res *= 1/x*1/x
x *= x
n //= 2
res *= 1/x*1/x
if f_p == 0:
return res
elif f_p > -1:
return res*fpower(t_x,f_p)
#function to calculate fractional power
def fpower(x, n):
pwr = 0
sign = 1
t_n = n
if x < 0:
x *= -1
sign = -1
while x > 2:
x = x/2
pwr += 1
if x >1:
pwr *= n
n *= -1
x = 1/x-1
elif x < 0.5 and x != 0:
x = sign*1/x
return fpower(x,-n)
elif x != 0:
x -= 1
res = 0
step = 1
coeff = 1
i = 0
while step > 1e-20:
step = coeff*power(x,i)
res += step
coeff *= (n-i)/(i+1)
i += 1
if step < 0:
step *= -1
mp = res*power(2,pwr)
if sign < 0:
pi = 3.141592653589793
real = mp*cos(t_n*pi)
img = mp*sin(t_n*pi)
if img != 0:
return complex(real,img)
else:
return real
else:
return mp
Output Comparison:
Inbuilt fn -
pow(89,99.354)
4.7829376579139805e+193
Own fn -
power(89,99.354)
4.7829376579139765e+193
Speed Comparison:
Inbuilt fn time -
pow(89,99.354)
0.00026869773864746094
Own fn time-
power(89,99.354)
0.0023398399353027344
There are a few things that can be said here. First of all, many Python standard library functions will be implemented in C, not in Python, so they will be faster. This makes sense, as the standard library will be called by a lot of code lots of times, so it pays off to implement such often-used code in a faster language.
Along with that goes additional optimization: this code is called so often that, besides implementing it in C, it makes sense to optimize this code. Compared to baseline Python, this includes writing "faster" C, but also what you get out of the box from your C compiler.
Some cursory research doesn't suggest this is the case, but exponentiation, as a common math operation, could also have some hardware acceleration that requires you to use specific intructions of the architecture you're running on - which you won't easily (if at all) be able to utilize in pure Python.
Then there's the matter of algorithms; once we leave the language difference aside, there are different ways to compute exponentiation, and without contrary evidence you should not assume that you have chosen the most efficient one. From you pointing out your algorithms it seems you have carefully chosen which ones to use, but still - when you're posing aquestion like this, don't simply assume you made an equally good choice as the standard library of a *looks at Wikipedia* 30 year old language.
Finally, don't forget that benchmarking methodology also plays a role in questions like this in general. a 6-7 times difference won't go away by changing your methodology, but it's worth remembering that testing your code against a very small number of inputs may not be representative of your code's performance in general, and different inputs will be representative for the built-in pow.
That's my thoughts on performance; as for accuracy, floating point errors can simply add up. As soon as you perform more than one operation on a decimal number, this will happen. (And remember, in general the first operation is representing the number in binary (IEEE 754) floating point format.) Wikipedia gives the example if squaring 0.1; 0.1 can not be represented precisely in binary, so you get your first rounding error here. As a result, squaring it will give you a less precise result than the best approximation for 0.01. As far as I can tell, you're not trying to comensate for roundign errors, and you're using a loop, so noticeable rounding errors are inevitable.
After I edited my code, I understand how to do it:
def sum_factors(n):
sum = 0
factor = 1
# Return the sum of all factors of n, not including n
while n!=0 and factor < n:
if n % factor == 0:
sum = sum + factor
factor = factor + 1
else:
factor = factor + 1
return sum
My initial code could not sum the factors but I don't understand why:
def sum_divisors(n):
sum = 0
factor = 1
# Return the sum of all divisors of n, not including n
while n % factor == 0 and factor < n:
sum = sum + factor
factor = factor + 1
return sum
Could you please explain why my initial code didn't work?
Your while loop writes
while n % factor == 0 and factor < n:
This would mean that once n % factor test condition is false, the code will break out of the while loop.
Let's use 10 as an example.
10 % 1 equals zero and 10 % 2 equals 0. But 10 % 3 does not equal 0. This means we break out of the while loop once factor gets to 3.
The answer we get would then be the sum of 1 and 2 which would be incorrect.
The initial code put a strong emphasize on the condition while n % factor == 0 which is not a necessary condition to end the while loop.
Sometimes, it helps to add some debugging output to a Python program:
def sum_divisors(n):
sum = 0
factor = 1
# Return the sum of all divisors of n, not including n
print(f"factor = {factor}")
while n % factor == 0 and factor < n:
sum = sum + factor
factor = factor + 1
print(f"factor = {factor}")
return sum
print(sum_divisors(30))
Output
factor = 1
factor = 2
factor = 3
factor = 4
6
Notes
As we can see, the while loop exits when it finds a number that is not a factor.
Refactoring
I noticed that you have duplicate code in your if-else block. Whenever this happens, you can move the common code outside:
if n % factor == 0:
sum = sum + factor
factor = factor + 1
I am trying to define a function which will approximate pi in python using one of Euler's methods. His formula is as follows:
My code so far is this:
def pi_euler1(n):
numerator = list(range(2 , n))
for i in numerator:
j = 2
while i * j <= numerator[-1]:
if i * j in numerator:
numerator.remove(i * j)
j += 1
for k in numerator:
if (k + 1) % 4 == 0:
denominator = k + 1
else:
denominator = k - 1
#Because all primes are odd, both numbers inbetween them are divisible by 2,
#and by extension 1 of the 2 numbers is divisible by 4
term = numerator / denominator
I know this is wrong, and also incomplete. I'm just not quite sure what the TypeError that I mentioned earlier actually means. I'm just quite stuck with it, I want to create a list of the terms and then find their products. Am I on the right lines?
Update:
I have worked ways around this, fixing the clearly obvious errors that were prevalent thanks to msconi and Johanc, now with the following code:
import math
def pi_euler1(n):
numerator = list(range(2 , 13 + math.ceil(n*(math.log(n)+math.log(math.log(n))))))
denominator=[]
for i in numerator:
j = 2
while i * j <= numerator[-1]:
if (i * j) in numerator:
numerator.remove(i * j)
j += 1
numerator.remove(2)
for k in numerator:
if (k + 1) % 4 == 0:
denominator.append(k+1)
else:
denominator.append(k-1)
a=1
for i in range(n):
a *= numerator[i] / denominator[i]
return 4*a
This seems to work, when I tried to plot a graph of the errors from pi in a semilogy axes scale, I was getting a domain error, but i needed to change the upper bound of the range to n+1 because log(0) is undefined. Thank you guys
Here is the code with some small modifications to get it working:
import math
def pi_euler1(n):
lim = n * n + 4
numerator = list(range(3, lim, 2))
for i in numerator:
j = 3
while i * j <= numerator[-1]:
if i * j in numerator:
numerator.remove(i * j)
j += 2
euler_product = 1
for k in numerator[:n]:
if (k + 1) % 4 == 0:
denominator = k + 1
else:
denominator = k - 1
factor = k / denominator
euler_product *= factor
return euler_product * 4
print(pi_euler1(3))
print(pi_euler1(10000))
print(math.pi)
Output:
3.28125
3.148427801913721
3.141592653589793
Remarks:
You only want the odd primes, so you can start with a list of odd numbers.
j can start with 3 and increment in steps of 2. In fact, j can start at i because all the multiples of i smaller than i*i are already removed earlier.
In general it is very bad practise to remove elements from the list over which you are iterating. See e.g. this post. Internally, Python uses an index into the list over which it iterates. Coincidently, this is not a problem in this specific case, because only numbers larger than the current are removed.
Also, removing elements from a very long list is very slow, as each time the complete list needs to be moved to fill the gap. Therefore, it is better to work with two separate lists.
You didn't calculate the resulting product, nor did you return it.
As you notice, this formula converges very slowly.
As mentioned in the comments, the previous version interpreted n as the limit for highest prime, while in fact n should be the number of primes. I adapted the code to rectify that. In the above version with a crude limit; the version below tries a tighter approximation for the limit.
Here is a reworked version, without removing from the list you're iterating. Instead of removing elements, it just marks them. This is much faster, so a larger n can be used in a reasonable time:
import math
def pi_euler_v3(n):
if n < 3:
lim = 6
else:
lim = n*n
while lim / math.log(lim) / 2 > n:
lim //= 2
print(n, lim)
numerator = list(range(3, lim, 2))
odd_primes = []
for i in numerator:
if i is not None:
odd_primes.append(i)
if len(odd_primes) >= n:
break
j = i
while i * j < lim:
numerator[(i*j-3) // 2] = None
j += 2
if len(odd_primes) != n:
print(f"Wrong limit calculation, only {len(odd_primes)} primes instead of {n}")
euler_product = 1
for k in odd_primes:
denominator = k + 1 if k % 4 == 3 else k - 1
euler_product *= k / denominator
return euler_product * 4
print(pi_euler_v2(100000))
print(math.pi)
Output:
3.141752253548891
3.141592653589793
In term = numerator / denominator you are dividing a list by a number, which doesn't make sense. Divide k by the denominator in the loop in order to use the numerator element for each of the equation's factors one by one. Then you could multiply them repeatedly to the term term *= i / denominator, which you initialize in the beginning as term = 1.
Another issue is the first loop, which won't give you the first n prime numbers. For example, for n=3, list(range(2 , n)) = [2]. Therefore, the only prime you will get is 2.
I am not sure whether this question was posted before, after searching it, I cannot find it.
Question: Give one number, to print all factor product.
Example:
Given number: 20
Output: 1 * 20
2 * 10
2 * 2 * 5
4 * 5
Given number: 30
Output: 1 * 30
2 * 15
2 * 3 * 5
3 * 10
5 * 6
Here are my thoughts:
Solution 1.
step 1) First, get all prime factors of this number
def get_prime_factors(n):
factors = []
if n == 0:
return factors
# Get the number of 2s that divide n
while n%2 == 0:
factors.append(2)
n /= 2
# n must be odd
for i in range(3, int(ceil(sqrt(n))), 2):
while n%i == 0:
factors.append(i)
n /= i
# handle the case n is prime number greater than 2s
if n > 2:
factors.append(n)
return factors
step 2) Then get the combination of those factors
I plan to get all factor product through combination, however, I am stuck in how to handle those duplicate factors in this case? (question 1)
Solution 2:
Solve it through backtracking method.
def get_factors_recv(n, cur_ret, ret):
for i in range(2, int(ceil(sqrt(n)))):
if n%i == 0:
fact_arr = [i, n/i]
# add the current value to current result
cur_ret.extend(fact_arr)
if sorted(cur_ret) not in ret:
ret.append(sorted(cur_ret))
# backtracking
cur_ret = cur_ret[:-2]
get_factors_recv(n/i, cur_ret + [i], ret)
def get_all_factors_product(n):
if n == 0:
return '';
result = []
# push the simple factor multiplier
result.append([1, n])
get_factors_recv(n, [], result)
return result
I want to know is there any optimization for the above codes? (Question 2)
Is there any better solution to solve it? (Question 3)
A simple while loop can solve your first problem of dupicates. Given a number:
num_list = []
i = 2;
num = 72*5*5*19*10
while i <=num:
if(num%i == 0):
num_list.append(i)
num = num/i
else:
i = i + 1
print num_list
num_list will contain the factors. The idea is to not increase the index variable untill the number is no longer divisible by it. Also the number keeps reducing after every division so the loop will actually run a lot less iterations than the actual number. Instead of
while i<=num
you can also use
while i<=num/2
This is correct mathematically and results in further reduction of no of iterations.
This will give you all the factors.
Hope this helps.
number = 30
factors = []
for i in range(1, number+1):
if number%i == 0:
factors.append(i)
print factors
I am trying to find an efficient way to compute Euler's totient function.
What is wrong with this code? It doesn't seem to be working.
def isPrime(a):
return not ( a < 2 or any(a % i == 0 for i in range(2, int(a ** 0.5) + 1)))
def phi(n):
y = 1
for i in range(2,n+1):
if isPrime(i) is True and n % i == 0 is True:
y = y * (1 - 1/i)
else:
continue
return int(y)
Here's a much faster, working way, based on this description on Wikipedia:
Thus if n is a positive integer, then φ(n) is the number of integers k in the range 1 ≤ k ≤ n for which gcd(n, k) = 1.
I'm not saying this is the fastest or cleanest, but it works.
from math import gcd
def phi(n):
amount = 0
for k in range(1, n + 1):
if gcd(n, k) == 1:
amount += 1
return amount
You have three different problems...
y needs to be equal to n as initial value, not 1
As some have mentioned in the comments, don't use integer division
n % i == 0 is True isn't doing what you think because of Python chaining the comparisons! Even if n % i equals 0 then 0 == 0 is True BUT 0 is True is False! Use parens or just get rid of comparing to True since that isn't necessary anyway.
Fixing those problems,
def phi(n):
y = n
for i in range(2,n+1):
if isPrime(i) and n % i == 0:
y *= 1 - 1.0/i
return int(y)
Calculating gcd for every pair in range is not efficient and does not scales. You don't need to iterate throught all the range, if n is not a prime you can check for prime factors up to its square root, refer to https://stackoverflow.com/a/5811176/3393095.
We must then update phi for every prime by phi = phi*(1 - 1/prime).
def totatives(n):
phi = int(n > 1 and n)
for p in range(2, int(n ** .5) + 1):
if not n % p:
phi -= phi // p
while not n % p:
n //= p
#if n is > 1 it means it is prime
if n > 1: phi -= phi // n
return phi
I'm working on a cryptographic library in python and this is what i'm using. gcd() is Euclid's method for calculating greatest common divisor, and phi() is the totient function.
def gcd(a, b):
while b:
a, b=b, a%b
return a
def phi(a):
b=a-1
c=0
while b:
if not gcd(a,b)-1:
c+=1
b-=1
return c
Most implementations mentioned by other users rely on calling a gcd() or isPrime() function. In the case you are going to use the phi() function many times, it pays of to calculated these values before hand. A way of doing this is by using a so called sieve algorithm.
https://stackoverflow.com/a/18997575/7217653 This answer on stackoverflow provides us with a fast way of finding all primes below a given number.
Oke, now we can replace isPrime() with a search in our array.
Now the actual phi function:
Wikipedia gives us a clear example: https://en.wikipedia.org/wiki/Euler%27s_totient_function#Example
phi(36) = phi(2^2 * 3^2) = 36 * (1- 1/2) * (1- 1/3) = 30 * 1/2 * 2/3 = 12
In words, this says that the distinct prime factors of 36 are 2 and 3; half of the thirty-six integers from 1 to 36 are divisible by 2, leaving eighteen; a third of those are divisible by 3, leaving twelve numbers that are coprime to 36. And indeed there are twelve positive integers that are coprime with 36 and lower than 36: 1, 5, 7, 11, 13, 17, 19, 23, 25, 29, 31, and 35.
TL;DR
With other words: We have to find all the prime factors of our number and then multiply these prime factors together using foreach prime_factor: n *= 1 - 1/prime_factor.
import math
MAX = 10**5
# CREDIT TO https://stackoverflow.com/a/18997575/7217653
def sieve_for_primes_to(n):
size = n//2
sieve = [1]*size
limit = int(n**0.5)
for i in range(1,limit):
if sieve[i]:
val = 2*i+1
tmp = ((size-1) - i)//val
sieve[i+val::val] = [0]*tmp
return [2] + [i*2+1 for i, v in enumerate(sieve) if v and i>0]
PRIMES = sieve_for_primes_to(MAX)
print("Primes generated")
def phi(n):
original_n = n
prime_factors = []
prime_index = 0
while n > 1: # As long as there are more factors to be found
p = PRIMES[prime_index]
if (n % p == 0): # is this prime a factor?
prime_factors.append(p)
while math.ceil(n / p) == math.floor(n / p): # as long as we can devide our current number by this factor and it gives back a integer remove it
n = n // p
prime_index += 1
for v in prime_factors: # Now we have the prime factors, we do the same calculation as wikipedia
original_n *= 1 - (1/v)
return int(original_n)
print(phi(36)) # = phi(2**2 * 3**2) = 36 * (1- 1/2) * (1- 1/3) = 36 * 1/2 * 2/3 = 12
It looks like you're trying to use Euler's product formula, but you're not calculating the number of primes which divide a. You're calculating the number of elements relatively prime to a.
In addition, since 1 and i are both integers, so is the division, in this case you always get 0.
With regards to efficiency, I haven't noticed anyone mention that gcd(k,n)=gcd(n-k,n). Using this fact can save roughly half the work needed for the methods involving the use of the gcd. Just start the count with 2 (because 1/n and (n-1)/k will always be irreducible) and add 2 each time the gcd is one.
Here is a shorter implementation of orlp's answer.
from math import gcd
def phi(n): return sum([gcd(n, k)==1 for k in range(1, n+1)])
As others have already mentioned it leaves room for performance optimization.
Actually to calculate phi(any number say n)
We use the Formula
where p are the prime factors of n.
So, you have few mistakes in your code:
1.y should be equal to n
2. For 1/i actually 1 and i both are integers so their evaluation will also be an integer,thus it will lead to wrong results.
Here is the code with required corrections.
def phi(n):
y = n
for i in range(2,n+1):
if isPrime(i) and n % i == 0 :
y -= y/i
else:
continue
return int(y)