【问题标题】:Checking for the nth prime number between 1 and 1,000,000, must compute 1,000,000th in under 3 minutes检查 1 到 1,000,000 之间的第 n 个素数,必须在 3 分钟内计算出第 1,000,000 个
【发布时间】:2014-12-07 16:44:49
【问题描述】:

我有这个,它有效。数字 100000+ 只需要大量时间,我希望将其减少,以便它可以在不到 3 分钟的时间内计算出第 1,000,000 个素数。我已经设置它,以便我们的数字(chk)只有数字(奇数)被分成它,以检查可分性,直到 chk 的平方根。该程序设置为查找第 n 个素数,直到第 1000000 个。谢谢。

goal=int(input("Enter a number n, 1-1,000,000 to find the nth prime number."))  #how many primes we need to find

if goal>1000000:         #closes the program if the number doesn't fit the parameters
    exit()
if goal==1:              #takes care of the first prime, which is 2
    print("2")
if goal==2:              #and then the second, which is 3
    print("3")

chk=5         #the next odd number after 3, which is already taken care of above
primes=2    #the number of primes recorded, after counting 2 and 3.
x=0         #the last recorded prime number
while primes<goal: 
    if  chk<9:     #if the number is odd and below 9....
        primes+=1  #it's prime
        x=chk      #record that number
        chk+=2     #and check the next odd number

    else:              #if it's =>9......
        odds=3         #check to see if it's divisible by the smallest odd number
        sqrtk=chk**.5  #all the way up to the square root of chk

        while odds<sqrtk or odds==sqrtk:   #if at any time...
            if chk%odds==0:                #...chk is divisible by this odd number....
                chk+=2                     #then raise the value of chk to the next odd number
                break                      #and start the check from the beginning with next k
            else:            #if not...
                odds+=2         #check to see if it's divisible by the next odd number. 

        if odds>sqrtk:             #if chk isn't divisible by any odds up to the square root of chk     
                primes+=1        #we have a prime number
                x=chk         #record that number
                chk+=2        #check the next odd number to see if it's prime
                odds=3         #and reset odds back to 3 to use it next time


if primes==goal:                  #once we've reached the desired amount of prime numbers
    print("The",goal,"prime number is:",x)      #print that prime number

【问题讨论】:

  • 这属于codereview
  • 谢谢。把它放在那里。
  • 这已被问过一百万次,无论是作为数学问题还是作为编程问题。请先对问题进行一些研究。

标签: python math


【解决方案1】:

更好的方法是生成一个质数列表,并检查该数字是否可以除以该列表中的某个数字

list = [ ]

while primes < goal: 
  found = false
  for n in list
    if chk % n = 0
      # is prime
      found = true
      break
  if not found
    list.append(chk)

要在更短的时间内生成列表,请尝试使用不同的编程语言。下面是 C++ 程序,它可以在 10 秒内生成第一个 1.000.000(取决于您使用的是什么)。

为此,我们考虑了一些数学假设: 1) 只检查奇数 2) 只检查小于当前数字平方根的数字

此外,还进行了一些 C 优化: 1)首先定义数组大小。通过这样做,我们不必处理重新分配内存的代价高昂的操作 2)使用“寄存器”来加速时间关键的处理块 3) 预计算 sqrt(chk) 以加快速度

#include <stdio.h>
#include <stdlib.h>
#include <vector>
#include <time.h>
#include <iostream>
#include <math.h>


#define NUMBERS 1000000


using namespace std;


main(int argc, char **argv)
{
  unsigned *list = (unsigned*)malloc(NUMBERS * sizeof(unsigned) );
  if(!list)
    exit(1);

  list[0] = 2;

  register unsigned primes = 1;
  unsigned goal = NUMBERS;
  unsigned chk = 3;

  clock_t tStart = clock();

  bool found;

  while(primes < goal) {
    found = false;
    register unsigned sq = sqrt(chk);
    for(register unsigned i = 1 ; i < primes ; i++) {
      if(list[i] > sq)
        break;
      if(chk % list[i] == 0) {
        found = true;
        break;
      }
    }
    if(!found) {
      list[primes++] = chk;
   }

    chk += 2;
  }


  printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);

  for(int i = 0 ; i < primes ; i++)
    cout << list[i] << "  ;  ";
  cout << endl << endl;

  free(list);
}

python中的相同程序运行时间为126s,低于180s。

import sys
import os
import datetime
import csv
import time
import math


list = [ 2 ]

goal = 1000000
primes = 1

chk = 3

start = time.time()

while primes < goal:
  found = False
  sq = math.sqrt(chk)
  for n in list:
    if sq < n:
      break
    if chk % n == 0:
      # is prime
      found = True
      break
  if not found:
    list.append(chk)
    primes = primes + 1

  chk = chk + 2

end = time.time()
print end - start

【讨论】:

  • 这不是让它检查 n 是否均分到 chk,这意味着 chk 不是素数,然后将该非素数添加到列表中?
  • 啊啊啊,如果没有找到。明白了。
  • 另外,你需要从2开始检查
【解决方案2】:

我(几乎)完全修改了代码,将所有素数添加到一个列表中,并且只检查这些数字是否均分到我们正在检查的数字中。它运行得更快,但仍然无法在 3 分钟内计算 1,000,000。

另外,我想写这个而不需要导入任何库。时间只是我可以测试的,当然,时间。

import time
goal = int(input("Enter a number n, 1-1,000,000 to find the nth prime number."))
start = time.time()
if goal > 1000000:
    exit()

if goal > 4:
    lst = [2, 3, 5, 7]
    chk = 11
    primes = 4
    while primes < goal:
        for n in lst:
            if n > chk**.5:
                lst.append(chk)
                primes += 1
                break
            if chk % n == 0:
                break
        chk += 2

    else:
        print("The", str(goal), "prime number is:", str(chk - 2))

else:
    if goal == 1:
        print("2")
    if goal == 2:
        print("3")
    if goal == 3:
        print("5")
    if goal == 4:
        print("7")
elapsed = (time.time() - start)
print(elapsed)

【讨论】:

  • FWIW,使用 prime sieve 在 2.00GHz Pentium 4 上,我可以在大约 12 秒内用十几行代码完成此操作。(如果我不在网上听,它可能会运行得更快音乐)。
【解决方案3】:

如果您只关心前一百万个素数,最简单的解决方案是使用埃拉托色尼筛法预先计算前一百万个素数的列表,然后索引到列表中以找到第 n 个素数。这是一个简单的埃拉托色尼筛法:

def primes(n): # sieve of eratosthenes
    i, p, ps, m = 0, 3, [2], n // 2
    sieve = [True] * m
    while p <= n:
        if sieve[i]:
            ps.append(p)
            for j in range((p*p-3)/2, m, p):
                sieve[j] = False
        i, p = i+1, p+2
    return ps

第 100 万个素数是 15485863,所以预先计算并存储第 100 万个素数:

ps = primes(15485863)

那么你就可以很容易地查到第n个素数了:

def nthPrime(n):
    return ps[n-1]

这里有一些例子:

>>> nthPrime(1)
2
>>> nthPrime(10000)
104729
>>> nthPrime(1000000)
15485863

预先计算前一百万个素数只需几秒钟,查找第 n 个素数是即时的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 2019-04-11
    • 2016-09-19
    • 2012-03-26
    • 2021-10-16
    • 2019-10-22
    相关资源
    最近更新 更多