How to implement an efficient infinite generator of prime numbers in Python?

后端 未结 13 2240
醉酒成梦
醉酒成梦 2020-11-22 01:50

This is not a homework, I am just curious.

INFINITE is the key word here.

I wish to use it as for p in primes(). I believe that this is a built-

13条回答
  •  爱一瞬间的悲伤
    2020-11-22 02:29

    Since the OP asks for an efficient implementation, here's a significant improvement to the active state 2002 code by David Eppstein/Alex Martelli (seen here in his answer): don't record a prime's info in the dictionary until its square is seen among the candidates. Brings space complexity down to below O(sqrt(n)) instead of O(n), for n primes produced ( π(sqrt(n log n)) ~ 2 sqrt(n log n) / log(n log n) ~ 2 sqrt(n / log n) ). Consequently, time complexity is also improved, i.e. it runs faster.

    Creates a "sliding sieve" as a dictionary of current multiples of each base prime (i.e. below the sqrt of the current production point), together with their step values:

    from itertools import count
                                             # ideone.com/aVndFM
    def postponed_sieve():                   # postponed sieve, by Will Ness      
        yield 2; yield 3; yield 5; yield 7;  # original code David Eppstein, 
        sieve = {}                           #   Alex Martelli, ActiveState Recipe 2002
        ps = postponed_sieve()               # a separate base Primes Supply:
        p = next(ps) and next(ps)            # (3) a Prime to add to dict
        q = p*p                              # (9) its sQuare 
        for c in count(9,2):                 # the Candidate
            if c in sieve:               # c's a multiple of some base prime
                s = sieve.pop(c)         #     i.e. a composite ; or
            elif c < q:  
                 yield c                 # a prime
                 continue              
            else:   # (c==q):            # or the next base prime's square:
                s=count(q+2*p,2*p)       #    (9+6, by 6 : 15,21,27,33,...)
                p=next(ps)               #    (5)
                q=p*p                    #    (25)
            for m in s:                  # the next multiple 
                if m not in sieve:       # no duplicates
                    break
            sieve[m] = s                 # original test entry: ideone.com/WFv4f
    

    (the older, original code here was edited to incorporate changes as seen in the answer by Tim Peters, below). see also this for a related discussion.

    Similar 2-3-5-7 wheel-based code runs ~ 2.15x faster (which is very close to the theoretical improvement of 3/2 * 5/4 * 7/6 = 2.1875).

提交回复
热议问题