Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Improving pure Python prime sieve by recurrence formula

I am trying to optimize further the champion solution in prime number thread by taking out the complex formula for sub-list length. len() of the same subsequence is too slow as len is expensive and generating the subsequence is expensive. This looks to slightly speed up the function but I could not yet take away the division, though I do the division only inside the condition statement. Of course I could try to simplify the length calculation by taking out the optimization of starting marking for n instead of n*n...

I replaced division / by integer division // to be compatible with Python 3 or

from __future__ import division

Also I would be interesting if this recurrence formula could help to speed up the numpy solution, but I have not experience of using numpy much.

If you enable psyco for the code, the story becomes completely different, however and Atkins sieve code becomes faster than this special slicing technique.

import cProfile

def rwh_primes1(n):
    # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    """ Returns  a list of primes < n """
    sieve = [True] * (n//2)
    for i in xrange(3,int(n**0.5)+1,2):
        if sieve[i//2]:
            sieve[i*i//2::i] = [False] * ((n-i*i-1)//(2*i)+1)
    return [2] + [2*i+1 for i in xrange(1,n/2) if sieve[i]]

def primes(n):
    # http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
    # recurrence formula for length by amount1 and amount2 Tony Veijalainen 2010
    """ Returns  a list of primes < n """
    sieve = [True] * (n//2)
    amount1 = n-10
    amount2 = 6

    for i in xrange(3,int(n**0.5)+1,2):
        if sieve[i//2]:
             ## can you make recurrence formula for whole reciprocal?
            sieve[i*i//2::i] = [False] * (amount1//amount2+1)
        amount1-=4*i+4
        amount2+=4

    return [2] + [2*i+1 for i in xrange(1,n//2) if sieve[i]]

numprimes=1000000
print('Profiling')
cProfile.Profile.bias = 4e-6
for test in (rwh_primes1, primes):
    cProfile.run("test(numprimes)")

Profiling (not so much difference between versions)

         3 function calls in 0.191 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.006    0.006    0.191    0.191 <string>:1(<module>)
        1    0.185    0.185    0.185    0.185 myprimes.py:3(rwh_primes1)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


         3 function calls in 0.192 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.006    0.006    0.192    0.192 <string>:1(<module>)
        1    0.186    0.186    0.186    0.186 myprimes.py:12(primes)
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

Interestingly by increasing the limit to 10**8 and putting timing decorator to functions removing the profiling:

rwh_primes1 took 23.670 s
primes took 22.792 s
primesieve took 10.850 s

Interestingly if you do not produce list of primes but return the sieve itself the time is around half from number list version.

like image 995
Tony Veijalainen Avatar asked Jul 19 '10 22:07

Tony Veijalainen


1 Answers

You could do a wheel optimisation. Multiples of 2 and 3 aren't primes, so dont store them at all. You could then start from 5 and skip multiples of 2 and 3 by incrementing in steps of 2,4,2,4,2,4 etc..

Below is a C++ code for it. Hope this helps.

void sieve23()
{
    int lim=sqrt(MAX);
    for(int i=5,bit1=0;i<=lim;i+=(bit1?4:2),bit1^=1)
    {
        if(!isComp[i/3])
        {
            for(int j=i,bit2=1;;)
            {
                j+=(bit2?4*i:2*i);
                bit2=!bit2;
                if(j>=MAX)break;
                isComp[j/3]=1;
            }
        }
    }
}
like image 120
jack_carver Avatar answered Nov 05 '22 11:11

jack_carver