【问题标题】:Find out 20th, 30th, nth prime number. (I'm getting 20th but not 30th?) [Python]找出第 20、30、n 个素数。 (我得到了第 20 名而不是第 30 名?)[Python]
【发布时间】:2011-01-01 00:57:27
【问题描述】:

问题是找到第 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,因为只有奇数可以是素数数字。我知道还有其他方法可以解决这个问题,例如素数定理,但我想知道这种方法有什么问题。另外,如果您有任何优化想法,请提出建议。

谢谢

【问题讨论】:

  • 元组是不可变的,您每次都在制作元组的副本,而不是将其初始化为列表 (primes=[]) 和用户 primes.append() - 这不应该太虽然对速度有很大影响...
  • 嗯...好问题。可能不是最快的实现。我一直想构建一个高效的素数生成器,只要它有足够的内存来计算它需要的东西,它就可以继续运行。著名的 Sieve 将不起作用 - 您不想在开始之前选择您查看的数字的上限。但是,每个检查的新数字的 O(n) 复杂度也是垃圾。理想情况下,您希望到目前为止计算出一个列表和一组素数,然后对它们进行模测试。我还没有完全写出来……我知道 Haskell 语言有一个素数生成器。
  • @SilentGhost 为什么? @Kimvais我知道,我每次都在创建一个新元组,但是使用列表也不能解决我的问题@Ipthnc这正是我的想法,但即使我无法写下来,也许我会多花点时间tm。为此我的问题仍然没有解决
  • 这听起来有点像欧拉计划问题。
  • 一般性说明:将 n 除以直到 n 的平方根的所有数字就足以确定 n 是否为素数(您正在测试 n)

标签: python primes


【解决方案1】:

在 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]

【讨论】:

  • 实际上,这段代码不是埃拉托色尼筛法的实现,因为它计算每个候选者的余数除以已经找到的每个素数... SoE 执行无除法根本就只是加法(这是以固定增量划掉数字所必需的)。 Melissa E. O'Neill 有一篇不错的论文——“The Genuine Sieve of Eratosthenes”——讨论了这种类型的幼稚实现与在 Haskell 上下文中真正的 SoE 之间的区别,尽管它根本不是 Haskell - 特定的,甚至是 FP 特定的,并且可以很容易地用 Python 重写。
  • 继续超过评论长度限制...在适当的 SoE 和这种幼稚的筛子之间存在巨大的性能差异,尽管这当然不会阻止幼稚筛出在测试 Python 的生成器实现的上下文中非常合适。 :-)
  • @Michal。很好注意!它确实不是真正的 Sieve。谢谢。
【解决方案2】:

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

当您找到一个除数 (candidate % x == 0) 后,您会增加候选者,但您不会对 x 做任何事情。这会导致两个问题:

  1. candidate 可能有一个除数,但它比任何经过测试的 x 都小——因为循环的下一次迭代中的测试从 x 开始,比 x 之前的值高一个;不在2
  2. candidate 可能有一个除数,但它大于x 得到的值,因为您将 x2 的值中取为 candidate 的值开始循环

【讨论】:

    【解决方案3】:

    我不认为这是在测试你认为它在测试的东西。看起来你想说“对于 2 和我的候选人之间的每个数字,检查候选人是否能被那个数字整除”。然而,当你找到一个素数 (candidate%x == 0) 时,你只是在增加候选者——你仍然需要重新开始你的“for x in ...”循环,因为候选者已经改变了。

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

    【讨论】:

      【解决方案4】:

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

      当你在寻找下一个候选人时,你总是可以这样写(代码 sn-p 在 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;
      }
      

      【讨论】:

        【解决方案5】:

        在声明中:

        for x in range(2,candidate)
        

        你可以通过扫描到 sqrt(candidate) 来减少迭代次数

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

        【讨论】:

          【解决方案6】:

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

          1. 以 5 结尾,因为它们可以被 5 整除。
          2. 由相同的数字组成,例如22、33、44、55、66 等,因为它们可以被 11 整除。

          不要忘记添加 5 和 11 作为素数!

          【讨论】:

          • 如果除数可以是以前收集的素数的列表,那将很容易。我想我会采用这种方法。现在就用代码把它写下来!!
          • @Alex:假设 OP 使用二进制计算机,检查最后 10 个基数是否为 5 归结为首先除以 5。你的第二点也有类似的论点。
          • #2 在二进制计算机上并不是真正的优化。 #1 可以概括为实现称为“轮子”的东西。你取前 k 个素数,例如 2、3、5,然后只尝试不是 0 模任何这些素数的候选。因此,模 30 意味着您只尝试具有以下余数模 2*3*5 的候选人:[1, 7, 11, 13, 17, 19, 23, 29]。因此,你可以有这样的东西: primes=[2,3,5]; for base in xrange(0, 10000000, 2*3*5): for rem_mod30 in [1, 7, 11, 13, 17, 19, 23, 29]: Candidate = base + rem_mod30 # 检查候选人是否为素数跨度>
          【解决方案7】:

          除非我错了,否则无论是否找到除数,您总是将当前候选添加到素数列表中。您要附加到素数列表的代码(撇开前面所做的不可变元组注释)不在整数除数测试范围内,因此始终运行。

          【讨论】:

            【解决方案8】:

            如果您想要任何远程高效的东西,请拨打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]
            

            【讨论】:

            • 我已经看到了,但是如果我想要前 20,000 个素数怎么办?那时很难选择MAX。另外,如果我想无限期地继续下去怎么办?
            • x 下方大约有 x/log x 素数,因此您只需计算 MAX。还有其他算法可以找到非常大的素数。
            【解决方案9】:

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

            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]
            

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

            【讨论】:

              【解决方案10】:

              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;
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2013-01-13
                • 2016-02-01
                • 1970-01-01
                • 1970-01-01
                • 2021-01-16
                • 1970-01-01
                • 2013-01-22
                • 2018-11-13
                相关资源
                最近更新 更多