[Tutor] primes

Kent Johnson kent37 at tds.net
Fri Mar 18 03:15:48 CET 2005


Max Noel wrote:
> #!/usr/bin/env python
> 
> import math
> import timeit
> 
> def primeConcise(limit):
>     return [2] + [x for x in xrange(3, limit, 2) if not [y for y in [2] 
> + range(3,x,2) if x%y==0]]
> 
> 
> def primeConciseOptimized(limit):
>     return [2] + [x for x in xrange(3, limit, 2) if not [y for y in [2] 
> + range(3,int(math.sqrt(x)), 2) if x%y==0]]

Hmm, I didn't know that 9 and 15 were prime...
When I'm doing timings like this I usually check the output. You can write a *very* fast algorithm 
if correctness does not count :-)

Here is a version that gives correct results at least up to limit=50:

def primeConciseOptimized(limit):
     return [2] + [x for x in xrange(3, limit, 2) if not [y for y in [2] + 
range(3,int(math.sqrt(x))+1, 2) if x%y==0]]

One reason your listPrimes() function is faster is that it short-circuits the test - as soon as a 
divisor is found for a candidate, no further testing is done. primeConciseOptimized() always tests 
all the candidate divisors.

In the spirit of useless optimizations of bad algorithms ;) I used itertools to make a 
short-circuiting version of primeConciseOptimized():

import itertools
def no(seq, pred=bool):
     '''Returns True if pred(x) is False for every element in the iterable
        From the itertools recipes. '''
     for elem in itertools.ifilter(pred, seq):
         return False
     return True

def primeConciseOptimized2(limit):
     return [2] + [x for x in xrange(3, limit, 2) if no(xrange(3,int(math.sqrt(x))+1, 2), lambda y: 
x%y==0)]

Note I don't bother testing for divisibility by 2 since the candidates are all odd. This allows 
using xrange() instead of range() for a significant improvement.

My times:
listPrimes 0.143752069048
primeConciseOptimized 0.586845814203
primeConciseOptimized2 0.391731351331

Kent

> 
> def isPrime(x, primeList):
>     limit = int(math.sqrt(x))
>     for i in primeList:
>         if x % i == 0:
>             return False
>         if i >= limit:
>             break
>     return True
> 
> def listPrimes(upperLimit):
>     listOfPrimes = [2]
>     for i in xrange(3, upperLimit, 2):
>         if isPrime(i, listOfPrimes):
>             listOfPrimes.append(i)
>     return listOfPrimes
> 
> 
> if __name__ == '__main__':
>     t1 = timeit.Timer('listPrimes(50000)', 'from __main__ import 
> listPrimes')
>     t2 = timeit.Timer('primeConciseOptimized(50000)', 'from __main__ 
> import primeConciseOptimized')
>     t3 = timeit.Timer('primeConcise(50000)', 'from __main__ import 
> primeConcise')
>     print t1.timeit(1)
>     print t2.timeit(1)
>     print t3.timeit(1)
> 
> 
> 
> -- Max
> maxnoel_fr at yahoo dot fr -- ICQ #85274019
> "Look at you hacker... A pathetic creature of meat and bone, panting and 
> sweating as you run through my corridors... How can you challenge a 
> perfect, immortal machine?"
> 
> _______________________________________________
> Tutor maillist  -  Tutor at python.org
> http://mail.python.org/mailman/listinfo/tutor
> 



More information about the Tutor mailing list