如何在Python中生成第1000个素数?

11 投票
13 回答
13242 浏览
提问于 2025-04-17 19:01
count = 0
i = 11

while count <= 1000 and i <= 10000:
    if i%2 != 0:
       if (i%3 == 0 or i%4 == 0 or i%5 == 0 or i%6 == 0 or i%7 == 0 or i%9 == 0):
           continue
       else:
           print i,'is prime.'
           count += 1
    i+=1

我正在尝试通过循环生成第1000个质数。我生成的质数是正确的,但我得到的最后一个质数并不是第1000个质数。我该如何修改我的代码来实现这个目标呢?提前感谢大家的帮助。

补充说明:我现在明白如何解决这个问题了。但能不能请大家解释一下,为什么下面的代码不工作?这是我在这里发布第二个代码之前写的代码。

count = 1
i = 3
while count != 1000:
    if i%2 != 0:
       for k in range(2,i):
          if i%k == 0:
            print(i)
            count += 1
            break
     i += 1

13 个回答

3

你确定你检查质数的方法是对的吗?一个常见的解决办法是写一个单独的“isPrime”函数,这个函数你可以确认它是有效的。

def isPrime(num):
    i = 0
    for factor in xrange(2, num):
        if num%factor == 0:
            return False
    return True

(还有一些方法可以让上面的函数更有效,比如只检查奇数,或者只检查小于平方根的数字等等。)

然后,要找到第n个质数,就要数出所有的质数,直到找到为止:

def nthPrime(n):
    found = 0
    guess = 1
    while found < n:
        guess = guess + 1
        if isPrime(guess):
            found = found + 1
    return guess
5

这里有几个明显的问题。首先,因为你是从11开始的,所以你已经跳过了前5个质数,因此计数应该从5开始。

更重要的是,你的质数检测算法根本行不通。对于这种简单的“埃拉托斯特尼筛法”质数检测,你必须记录所有小于i的质数。例如,你的算法会认为11 * 13 = 143是质数,但显然它不是。

PGsimple1 这里是你想要实现的质数检测的正确版本,但那里的其他算法要快得多。

9

我们来看看。

count = 1
i = 3
while count != 1000:
    if i%2 != 0:
       for k in range(2,i):
          if i%k == 0:        # 'i' is _not_ a prime!
            print(i)       # ??
            count += 1     # ??
            break
     i += 1          # should be one space to the left,
                     # for proper indentation

如果 i%k==0,那么 i不是一个质数。如果我们发现它不是质数,我们应该 (a) 打印出来,(b) 增加找到的质数计数器,(c) 我们确实应该退出 for 循环——没有必要再测试其他数字了。

另外,我们可以不测试 i%2,而是从 3 开始,每次加 2——这样得到的数字都是奇数。

所以,现在我们有了

count = 1
i = 3
while count != 1000:
    for k in range(2,i):
        if i%k == 0:       
            break
    else:
        print(i)
        count += 1
    i += 2        

for 循环后面的 else 只有在 for 循环没有提前退出时才会执行。

这个方法可以用,但效率太低,速度比必要的要慢很多。它会用所有小于这个数字的数字来测试,但其实只需要测试到它的平方根就够了。为什么呢?因为如果一个数字 n == p*q,其中 pq1n 之间,那么至少有一个 pq 不会大于 n 的平方根:如果它们都大于平方根,它们的乘积就会大于 n

所以 改进后的代码是

from math import sqrt

count = 1
i = 1
while count < 1000:
    i += 2
    for k in range(2, 1+int(sqrt(i+1))):
        if i%k == 0:       
            break
    else:
        # print(i) ,
        count += 1
        # if count%20==0: print ""
print i

试着用 range(2,i)(就像之前的代码那样)运行一下,看看它有多慢。对于1000个质数,它需要1.16秒,2000个质数需要4.89秒(3000个质数需要12.15秒)。但是使用平方根后,生成3000个质数只需0.21秒,生成10,000个质数需要0.84秒,生成20,000个质数需要2.44秒(增长速度的比较~ n2.1...2.2 对比 ~ n1.5)。

上面使用的算法被称为 试除法。为了使其成为最优的试除法,我们还需要一个改进,即只用质数进行测试。一个例子 可以在这里看到,这个方法 运行速度快了大约3倍,并且在实际复杂度上更好,达到 ~ n1.3


接下来是 埃拉托斯特尼筛法,它 速度相当快(对于20000个质数,比上面的“改进代码”快12倍,之后速度更快:它的实际增长速度为 ~ n1.1,用于生成 n 个质数,测量到 n = 1,000,000 个质数):

from math import log

count = 1 ; i = 1 ; D = {}
n = 100000                        # 20k:0.20s 
m = int(n*(log(n)+log(log(n))))   # 100k:1.15s 200k:2.36s-7.8M 
while count < n:                  #            400k:5.26s-8.7M 
        i += 2                    #            800k:11.21-7.8M 
        if i not in D:            #            1mln:13.20-7.8M (n^1.1)
            count += 1
            k = i*i
            if k > m:  break      # break, when all is already marked
            while k <= m:
                D[k] = 0 
                k += 2*i
while count < n:
        i += 2
        if i not in D: count += 1
if i >= m: print "invalid: top value estimate too small",i,m ; error
print i,m  

真正无限制的 增量“滑动”埃拉托斯特尼筛法 在这个范围内测试时速度还快了约1.5倍。

撰写回答