I am learning Python (I have some background in other languages, notably C, etc.), and I am attempting to write some simple functions as a way to reinforce what I have read in the Python tutorial. In particular, here are my attempts at a function which determines whether a number is composite:
def isComposite(n):
"""Straight loop."""
for x in range(2, int(math.sqrt(n)) + 1):
if n % x == 0:
return x
return False
_PrimeList = [2]
def isCompPL(n):
"""Recursive version."""
for x in _PrimeList:
if n % x == 0:
if n == x:
return False
return x
for x in range(_PrimeList[-1], int(math.sqrt(n)) + 1):
if not isCompPL(x):
if x > _PrimeList[-1]:
_PrimeList.append(x)
if n % x == 0:
return x
return False
def isCompSR(n):
"""Serialized recursive version."""
l = [n]
while (math.sqrt(l[0]) > _PrimeList[-1]):
l.insert(0, int(math.sqrt(l[0])))
l.insert(0, _PrimeList[-1] + 1)
while (len(l) > 2):
q = l.pop([0])
for x in range(q, l[0]):
for y in _PrimeList:
if x % y == 0:
break
else:
_PrimeList.append(x)
return isCompPL(n)
isComposite(n) is orders of magnitude faster than either isCompPL(n) or isCompSR(n) when _PrimeList starts as [2]. When _PrimeList contains all the primes up to the square root of n, then both isCompPL(n) and isCompSR(n) catch up and may be faster than isComposite(n), but not significantly so. More striking to me is that if I call isCompSR(511111111111), a subsequent call isCompSR(1111111111111) is still much slower than calling isComposite(1111111111111), without clearing _PrimeList after the first call to isCompSR.
Is there something hidden about the list operations in Python that makes these attempts not successful in terms of optimization, or is it just that I'm adding a lot of extra prime testing and I need to reduce that portion somehow?