简体   繁体   English

Python中的生成器生成素数

[英]generator in Python generating prime numbers

I need to generate prime numbers using generator in Python. 我需要在Python中使用生成器生成素数。 Here is my code: 这是我的代码:

def genPrimes():
    yield 2
    x=2
    while True:
        x+=1
        for p in genPrimes():
            if (x%p)==0:
                break
        else:
            yield x

I have a RuntimeError: maximum recursion depth exceeded after the 2nd prime.next() when I run it. 我有一个RuntimeError:当我运行它时,在第二个prime.next()之后超出了最大递归深度。

The fastest way to generate primes is with a sieve. 生成素数的最快方法是使用筛子。 Here we use a segmented Sieve of Eratosthenes to generate the primes, one by one with no maximum, in order; 在这里,我们使用分段的Eratosthenes筛子按顺序逐个生成素数,没有最大值; ps is the list of sieving primes less than the current maximum and qs is the offset of the smallest multiple of the corresponding ps in the current segment. ps是小于当前最大值的筛选素数列表, qs是当前段中相应ps的最小倍数的偏移量。

def genPrimes():
    def isPrime(n):
        if n % 2 == 0: return n == 2
        d = 3
        while d * d <= n:
            if n % d == 0: return False
            d += 2
        return True
    def init(): # change to Sieve of Eratosthenes
        ps, qs, sieve = [], [], [True] * 50000
        p, m = 3, 0
        while p * p <= 100000:
            if isPrime(p):
                ps.insert(0, p)
                qs.insert(0, p + (p-1) / 2)
                m += 1
            p += 2
        for i in xrange(m):
            for j in xrange(qs[i], 50000, ps[i]):
                sieve[j] = False
        return m, ps, qs, sieve
    def advance(m, ps, qs, sieve, bottom):
        for i in xrange(50000): sieve[i] = True
        for i in xrange(m):
            qs[i] = (qs[i] - 50000) % ps[i]
        p = ps[0] + 2
        while p * p <= bottom + 100000:
            if isPrime(p):
                ps.insert(0, p)
                qs.insert(0, (p*p - bottom - 1)/2)
                m += 1
            p += 2
        for i in xrange(m):
            for j in xrange(qs[i], 50000, ps[i]):
                sieve[j] = False
        return m, ps, qs, sieve
    m, ps, qs, sieve = init()
    bottom, i = 0, 1
    yield 2
    while True:
        if i == 50000:
            bottom = bottom + 100000
            m, ps, qs, sieve = advance(m, ps, qs, sieve, bottom)
            i = 0
        elif sieve[i]:
            yield bottom + i + i + 1
            i += 1
        else: i += 1

A simple isPrime using trial division is sufficient, since it will be limited to the fourth root of n . 使用试验除法的简单isPrime就足够了,因为它将限于n的第四个根。 The segment size 2 * delta is arbitrarily set to 100000. This method requires O(sqrt n ) space for the sieving primes plus constant space for the sieve. 段大小2 * delta任意设置为100000.该方法需要O(sqrt n )空间用于筛分素数加上筛子的恒定空间。

It is slower but saves space to generate candidate primes with a wheel and test the candidates for primality with an isPrime based on strong pseudoprime tests to bases 2, 7, and 61; 它是较慢的,但可以节省空间,以产生与车轮候选素数,并用测试素性候选人isPrime基于强伪测试,以碱基2,图7和61; this is valid to 2^32. 这对2 ^ 32有效。

def genPrimes(): # valid to 2^32
    def isPrime(n):
        def isSpsp(n, a):
            d, s = n-1, 0
            while d % 2 == 0:
                d /= 2; s += 1
            t = pow(a,d,n)
            if t == 1: return True
            while s > 0:
                if t == n-1: return True
                t = (t*t) % n; s -= 1
            return False
        for p in [2, 7, 61]:
            if n % p == 0: return n == p
            if not isSpsp(n, p): return False
        return True
    w, wheel = 0, [1,2,2,4,2,4,2,4,6,2,6,4,2,4,\
        6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,\
        2,4,6,2,6,6,4,2,4,6,2,6,4,2,4,2,10,2,10]
    p = 2; yield p
    while True:
        p = p + wheel[w]
        w = 4 if w == 51 else w + 1
        if isPrime(p): yield p

If you're interested in programming with prime numbers, I modestly recommend this essay at my blog. 如果你对使用素数编程感兴趣,我谦虚地在我的博客上推荐这篇文章

genPrimes() unconditionally calls itself with exactly the same arguments. genPrimes()无条件地使用完全相同的参数调用自身。 This leads to infinite recursion. 这导致无限递归。

Here is one way to do it using a (non-recursive) generator: 以下是使用(非递归)生成器执行此操作的一种方法:

def gen_primes():
    n = 2
    primes = set()
    while True:
        for p in primes:
            if n % p == 0:
                break
        else:
            primes.add(n)
            yield n
        n += 1

Note that this is optimized for simplicity and clarity rather than performance. 请注意,这是为了简化和清晰而不是性能而优化的。

A good, fast way to find primes. 找到素数的好方法。 n is the upper limit to stop searching. n是停止搜索的上限。

def prime(i, primes):
    for prime in primes:
        if not (i == prime or i % prime):
            return False
    primes.add(i)
    return i

def find_primes(n):
    primes = set([2])
    i, p = 2, 0
    while True:
        if prime(i, primes):
            p += 1
            if p == n:
                return primes
        i += 1

Very nice! 非常好! You just forgot to stop taking primes from the inner genPrimes() when the square root of x is reached. 当达到x平方根时,你只是忘了停止从内部genPrimes()获取素数。 That's all. 就这样。

def genPrimes():
    yield 2 
    x=2
    while True:
        x+=1
        for p in genPrimes():
            if p*p > x:        # 
                yield x        #
                break          # 
            if (x%p)==0:
                break
        # else:
        #    yield x

Without it, you slide off the deep end, or what's the expression. 如果没有它,你会从深层滑落,或者是什么表达。 When a snake eats its own tail, it must stop in the middle. 当蛇吃自己的尾巴时,它必须停在中间。 If it reaches its head, there's no more snake (well, the direction of eating here is opposite, but it still applies...). 如果它到达它的头部,就没有蛇了(好吧,这里的吃饭方向相反,但它仍然适用......)。

Just a bit more concise: 更简洁一点:

import itertools

def check_prime(n, primes):
    for p in primes:
        if not n % p:
            return False
    return True

def prime_sieve():
    primes = set()
    for n in itertools.count(2):
        if check_prime(n, primes):
            primes.add(n)
            yield n

And you can use it like this: 你可以像这样使用它:

g = prime_sieve()
   g.next()
=> 2
   g.next()
=> 3
   g.next()
=> 5
   g.next()
=> 7
   g.next()
=> 11

Here's a fast and clear imperative prime generator not using sieves: 这是一个快速而明确的命令式素数发生器,不使用筛子:

def gen_primes():
    n = 2
    primes = []
    while True:
        is_prime = True
        for p in primes:
            if p*p > n:
                break
            if n % p == 0:
                is_prime = False
                break
        if is_prime:
            primes.append(n)
            yield n
        n += 1

It is almost identical to NPE 's answer but includes a root test which significantly speeds up the generation of large primes. 它几乎与NPE的答案相同,但包括一个根测试,它显着加速了大质数的产生。 The upshot is the O(n) space usage for the primes list. 结果是primes列表的O(n)空间使用。

Here is a script that generates list of prime number from 2 to given number 这是一个脚本,它生成从2到给定数字的素数列表

from math import sqrt
next = 2
n = int(raw_input())
y = [i for i in range(2, n+1)]
while y.index(next)+1 != len(y) and next < sqrt(n):
    y = filter(lambda x: x%next !=0 or x==next, y)
    next = y[y.index(next)+1]
print y

This is just another implementation of Sieve of Eratosthenes . 这只是Eratosthenes筛选的另一个实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM