Both functions implement essentially the same algorithm. Therefore, their algorithmic complexity should be the same. The only difference would be in the details. The best way to answer your question is to examine concrete evidence.
Before we proceed, I'd like to point out a few issues with nu_of_factors1()
:
def nu_of_factors1(n):
result_set = set()
sqrtn = int(n**0.5) # Misnomer - it's a rounded-down square root
for i in range(1,sqrtn+1):
q, r = n/i, n%i # If r != 0, then q is wasted
# Should use // (integer division) instead
if r == 0: # Fixed indentation
result_set.add(q)
result_set.add(i)
return len(result_set)
Addressing those issues…
def nu_of_factors1b(n):
result_set = set()
for i in range(1, 1+int(n**0.5)):
if n % i == 0:
result_set.add(n // i)
result_set.add(i)
return len(result_set)
One analysis method would be to inspect the Python bytecode. I won't reproduce the results here, except to say that nu_of_factors2
produces bytecode that is about half the length of nu_of_factors1
.
import dis
dis.dis(nu_of_factors1) # Longest bytecode
dis.dis(nu_of_factors1b) # Slightly shorter
dis.dis(nu_of_factors2) # Much shorter
How does that translate to real-world performance? The only way to find out is to run it! Using the time
command in Unix…
$ time python -c 'from cr32686 import *; print nu_of_factors1(28937489274598123)'
4
real 0m35.412s
user 0m33.358s
sys 0m2.052s
$ time python -c 'from cr32686 import *; print nu_of_factors1b(28937489274598123)'
4
real 0m17.277s
user 0m15.276s
sys 0m1.999s
$ time python -c 'from cr32686 import *; print nu_of_factors2(28937489274598123)'
4
real 0m18.552s
user 0m16.492s
sys 0m2.057s
As you can see, the difference between the two approaches is dwarfed by the inefficiency caused by one implementation detail: the fact that nu_of_factors1()
performs many superfluous divisions and discards the results when the remainder is non-zero.
Of course, you can also perform the benchmarking using Python itself.