找出第20,第30,第n个素数。 (我要20岁但不是30岁?)[Python]

时间:2010-01-03 18:57:36

标签: python primes

问题是找到第1000个素数。我为此编写了以下python代码。问题是,我得到了10号,20号素数的正确答案,但之后每增加10分,就让我失去了一个。我无法在这里发现错误:(

count=1            #to keep count of prime numbers
primes=()          #tuple to hold primes
candidate=3        #variable to test for primes
while count<20:
    for x in range(2,candidate):
        if candidate%x==0:
            candidate=candidate+2
        else : pass
    primes=primes+(candidate,)            
    candidate=candidate+2
    count=count+1
print primes        
print "20th prime is ", primes[-1]

如果你想知道,count初始化为1因为我没有测试2作为素数(我从3开始)而candidate正在增加2因为只有奇数可以是素数。我知道还有其他解决这个问题的方法,比如素数定理,但我想知道这种方法有什么问题。如果您有任何优化,请建议。

谢谢

10 个答案:

答案 0 :(得分:8)

test_generators.py中有一个很好的Sieve of Eratosthenes生成器实现:

def intsfrom(i):
     while 1:
         yield i
         i += 1

def firstn(g, n):
     return [g.next() for i in range(n)]

def exclude_multiples(n, ints):
     for i in ints:
         if i % n:
             yield i    

def sieve(ints):
     prime = ints.next()
     yield prime
     not_divisible_by_prime = exclude_multiples(prime, ints)
     for p in sieve(not_divisible_by_prime):
         yield p

primes = sieve(intsfrom(2))

>>> print firstn(primes, 20)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71]

alt text

答案 1 :(得分:5)

有许多(!)需要使用Python代码进行改进,但要回答您的具体问题:

当你找到一个除数(candidate % x == 0)时,你增加了候选者,但你没有对x做任何事情。这可能会导致两个问题:

  1. candidate可能有一个除数,但它比任何被测试的x小 - 因为在循环的下一次迭代中测试的开始时x比值高一个x之前有过;不在2
  2. candidate可能有一个除数,但它比<{1}} 更大,因为你从x的值中取x 启动循环时的值2

答案 2 :(得分:3)

我不认为这是测试您认为它正在测试的内容。看起来你正试图说“对于2和我的候选人之间的每个数字,检查候选人是否可以被该数字整除”。但是,当你找到一个素数(候选%x == 0)时,你只是递增候选者 - 你仍然需要重新开始你的“for x in ...”循环,因为候选人已经改变了。 / p>

这就是我从代码中看到的内容;当然还有很多其他方法和其他优化方法可以在这里使用。

答案 3 :(得分:2)

很高兴知道每个大于3的素数都可以写成: 6K-1 / + 1。

当你正在寻找下一个候选人时,你总是可以写这样的东西(代码片段在C中):

a=1;
...
candidate=6*k+(a=(a==-1)?1:-1);
if(a==1){
           k++;
}

我不久前用过的函数来确定第n个素数,其中LIM是你要找的第n个数字(C代码):

int sol2(){
        int res,cnt,i,k,a;
        res=-1;
        i=1;
        cnt=3;
        k=1;
        a=1;
        while (1){
                if (util_isprime(cnt)){
                        i++;
                        if (i==LIM){
                                res=cnt;
                                break;
                        }
                }
                /* 6k+/-1 starting from 6*1-1 */
                cnt=6*k+(a=(a==-1)?1:-1);
                if(a==1){
                        k++;
                }
        }
        return res;
}

答案 4 :(得分:2)

声明中:

for x in range(2,candidate)

您可以通过扫描到sqrt(候选)来减少迭代次数

  

如果候选人可以被x整除,那么我们   可以为某些b写出candidate = x * b。如果是x   小于或等于b,然后是x   必须小于或等于   候选人的平方根

答案 5 :(得分:0)

至于优化,如果您确定要遵循此实现,则可以避免查看以下数字:

  1. 结束于5,因为它们可以被5整除。
  2. 由相同的数字组成,例如22,33,44,55,66等,因为它们可被11整除。
  3. 不要忘记添加5和11作为素数!

答案 6 :(得分:0)

除非我非常错误,否则无论是否找到除数,您总是将当前候选人添加到素数列表中。你附加到素数列表的代码(将前面提到的不可变元组注释放在一边)超出了整数除数的测试范围,因此总是运行。

答案 7 :(得分:0)

如果您想要任何远程效率的东西,请执行Sieve of Eratosthenes - 它就像现在一样简单。

MAX = 10000
candidates = [True] * MAX
candidates[0] = False
candidates[1] = False

primelist = []
for p,isprime in enumerate(candidates):
    if isprime:
        primelist.append(p)
        for n in range(2*p,MAX,p):
            candidates[n] = False

print primelist[1001]

答案 8 :(得分:0)

FYI ...我用以下代码解决了它,虽然它可以进行更多优化,我只想先以这种方式解决它。谢谢大家的帮助。

from math import *
primes=[2,3]
count=2
testnumber=5
while count<1000:

    flag=0
    for x in range(2,testnumber):
        if x<=sqrt(testnumber):
            if testnumber%x==0:
                #print testnumber , "is not a prime"
                flag=1

            else : pass
    if flag!=1:
        #print testnumber , "is a prime"
        primes=primes+[testnumber]
        count=count+1
    testnumber=testnumber+2


#print primes
print "1000th prime is ", primes[-1]

我现在将看看你们提到的所有其他算法

答案 9 :(得分:0)

c初学者

#include<stdio.h>
int main ()

{
int a,s,c,v,f,p,z;

while(scanf("%d",&f) !=EOF){
p=0;
for(z=1;p<f;z++){
                s=2;
                a=z;
                while(s<a){
                          if(a%s==0)s=a+1;
                          else s=s+1;
                          }
                if (s!=a+1)p++;

                }
printf("%d\n",a);
                            }

return 0;
}