I wrote this rather poor Python function for prime factorization:
import math
def factor(n):
for i in range(2, int(math.sqrt(n)+1)):
if not n % i:
return [i] + factor(n//i)
return [n]
and it worked as expected, now I was interested in whether the performance could be better when using an iterative approach:
def factor_it(n):
r = []
i = 2
while i < int(math.sqrt(n)+1):
while not n % i:
r.append(i)
n //= i
i +=1
if n > 1:
r.append(n)
return r
But what I observed (while the functions gave the same results) was that the iterative function took longer to run. At least I had the feeling, when doing this:
number = 31123478114123
print(factor(number))
print(factor_it(number))
so I measured:
setup = '''
import math
def factor(n):
for i in range(2, int(math.sqrt(n)+1)):
if not n % i:
return [i] + factor(n//i)
return [n]
def factor_it(n):
r = []
i = 2
while i < int(math.sqrt(n)+1):
while not n % i:
r.append(i)
n //= i
i +=1
if n > 1:
r.append(n)
return r
'''
import timeit
exec(setup)
number = 66666667*952381*290201
print(factor(number))
print(factor_it(number))
print(timeit.Timer('factor('+str(number)+')',setup=setup).repeat(1,1))
print(timeit.Timer('factor_it('+str(number)+')',setup=setup).repeat(1,1))
And this is what I got:
[290201, 952381, 66666667]
[290201, 952381, 66666667]
[0.19888348945642065]
[0.7451271022307537]
Why is the recursive approach in this case faster than the iterative one?
I use WinPython-64bit-3.4.4.2 (Python 3.4.4 64bits).
It’s because you’re recomputing sqrt
each time. This modification runs as fast as your recursive version:
def factor_it2(n):
r = []
i = 2
lim = int(math.sqrt(n)+1)
while i < lim:
while not n % i:
r.append(i)
n //= i
lim = int(math.sqrt(n)+1)
i += 1
if n > 1:
r.append(n)
return r
timeit
gives me these times:
factor 0.13133816363922143
factor_it 0.5705408816539869
factor_it2 0.14267319543853973
I think the tiny difference that remains is due to for … in range(…)
being faster than the equivalent while
loop, as the for
loop can use a generator instead of having to execute a bunch of comparisons.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With