Sieve of Eratosthenes - Finding Primes Python

前端 未结 17 2321
旧巷少年郎
旧巷少年郎 2020-11-22 04:40

Just to clarify, this is not a homework problem :)

I wanted to find primes for a math application I am building & came across Sieve of Eratosthenes approach.

17条回答
  •  鱼传尺愫
    2020-11-22 05:13

    Here's a version that's a bit more memory-efficient (and: a proper sieve, not trial divisions). Basically, instead of keeping an array of all the numbers, and crossing out those that aren't prime, this keeps an array of counters - one for each prime it's discovered - and leap-frogging them ahead of the putative prime. That way, it uses storage proportional to the number of primes, not up to to the highest prime.

    import itertools
    
    def primes():
    
        class counter:
            def __init__ (this,  n): this.n, this.current,  this.isVirgin = n, n*n,  True
                # isVirgin means it's never been incremented
            def advancePast (this,  n): # return true if the counter advanced
                if this.current > n:
                    if this.isVirgin: raise StopIteration # if this is virgin, then so will be all the subsequent counters.  Don't need to iterate further.
                    return False
                this.current += this.n # pre: this.current == n; post: this.current > n.
                this.isVirgin = False # when it's gone, it's gone
                return True
    
        yield 1
        multiples = []
        for n in itertools.count(2):
            isPrime = True
            for p in (m.advancePast(n) for m in multiples):
                if p: isPrime = False
            if isPrime:
                yield n
                multiples.append (counter (n))
    

    You'll note that primes() is a generator, so you can keep the results in a list or you can use them directly. Here's the first n primes:

    import itertools
    
    for k in itertools.islice (primes(),  n):
        print (k)
    

    And, for completeness, here's a timer to measure the performance:

    import time
    
    def timer ():
        t,  k = time.process_time(),  10
        for p in primes():
            if p>k:
                print (time.process_time()-t,  " to ",  p,  "\n")
                k *= 10
                if k>100000: return
    

    Just in case you're wondering, I also wrote primes() as a simple iterator (using __iter__ and __next__), and it ran at almost the same speed. Surprised me too!

提交回复
热议问题