I was doing timing with variations of function largest_prime_factor
. I was able to write a better one largest_prime_factor2
. There were some repetitions in the new function so I wrote another function largest_prime_factor3
.
I thought the 3rd one has to be faster than the 2nd because I broke it up into more functions but it wasn't faster but slower.
- I wanted to know whether my method of code reuse is good or not?
- Is there a better way of reusing code in Python?
- Did I miss something due to which the new function became slower?
My functions alongwith the testing()
function used to test all three.
def largest_prime_factor(num):
'''returns the largest prime factor of a number'''
ans = 0
if num % 2 == 0:
ans = 2
num /= 2
while num % 2 == 0:
num /= 2
i = 3
while i <= num:
if num % i == 0:
ans = i
num /= i
while num % i == 0:
num /= i
i += 2
return ans
def largest_prime_factor2(num):
'''returns the largest prime factor of a number'''
ans = 0
if num % 2:
pass
else:
ans = 2
while True:
num //= 2
if num % 2:
break
i = 3
while i <= num:
if num % i:
pass
else:
ans = i
while True:
num //= i
if num % i:
break
i += 2
return ans
def largest_prime_factor3(num):
'''returns the largest prime factor of a number'''
def check(j):
nonlocal ans
nonlocal num
if num % j:
return
ans = j
while True:
num //= j
if num % j:
return
ans = 0
check(2)
i = 3
while i <= num:
check(i)
i += 2
return ans
def testing():
from timeit import Timer
import random
def tests(f, times):
def test1(f):
f(random.randint(1, 1000))
def test2(f):
f(random.randint(100000, 1000000))
print(f.__name__)
print(Timer(lambda: test1(f)).timeit(number = times))
print(Timer(lambda: test2(f)).timeit(number = times//10))
print()
tests(largest_prime_factor, 10000)
tests(largest_prime_factor2, 10000)
tests(largest_prime_factor3, 10000)
if __name__ == "__main__":
testing()
The timing results that I found:
largest_prime_factor 0.338549207387318 16.599112750324068 largest_prime_factor2 0.21575289594063918 12.086949738861868 largest_prime_factor3 0.36032199674939847 18.893444539398857
This format of results is produced by the testing
function. See that for details.
2
. But you can create an iterable that first yields 2 and then only the odd numbers. For example usingitertools.chain
:for i in it.chain([2], range(3, num, 2)): ...
would do what you want. (Last remark: instead ofwhile True
you could usewhile n % i == 0
and remove thebreak
). – Bakuriu Jul 20 '13 at 15:58if
when timing that?for i in range(3, num, 2): while n %i == 0: ... n //= i
. Also, do not obsess to much about timing. Readable code is much better than a code that take 0.1 msec less. Havingwhile True
s around doesn't make code readable. – Bakuriu Jul 20 '13 at 16:03sqrt(n)
since they cannot be factors ofn
. the only case is whenn
is prime). – Bakuriu Jul 20 '13 at 16:09