在最短的时间内找到素数列表

时间:2012-05-21 18:47:28

标签: algorithm primes

我读了很多算法来查找素数,结论是如果数字不能被前面的任何素数整除,则数字是素数。

我无法找到更准确的定义。基于此,我编写了一个代码并且它表现令人满意,直到我传递的最大数量为1000000.但我相信有更快的算法可以找到比给定数字更小的所有素数。

以下是我的代码,我可以有更好的版本吗?

 public static void main(String[] args) {
    for (int i = 2; i < 100000; i++) {
        if (checkMod(i)) {
            primes.add(i);
        }
    }
}

private static boolean checkMod( int num) {
    for (int i : primes){
        if( num % i == 0){
            return false;
        }
    }
    return true;
}

7 个答案:

答案 0 :(得分:19)

你的素性测试中的好处是你只能按素数划分。

private static boolean checkMod( int num) {
    for (int i : primes){
        if( num % i == 0){
            return false;
        }
    }
    return true;
}

糟糕的是,你除以到目前为止发现的所有素数,也就是说,所有素数都小于候选者。这意味着对于低于一百万的最大素数999983,你除以78497个素数以发现这个数字是素数。这是很多工作。事实上,在这个算法中花费在素数上的工作占了所有工作的大约99.9%,当达到一百万时,更大的部分用于更高的限制。并且该算法几乎是二次的,以这种方式找到n的素数,你需要执行大约

n² / (2*(log n)²)

分裂。

一个简单的改进是提前停止分裂。假设n是一个复合数(即一个数字大于1且除数为1且n除数的除数),并且dn的除数。

现在,dn的除数意味着n/d是一个整数,也是n的除数:n/(n/d) = d。 因此,我们可以自然地将n的除数分组成对,每个除数d生成(d, n/d)对。

对于这样一对,有两种可能性:

  1. d = n/d,表示n = d²d = √n
  2. 两者不同,其中一个比另一个小,比如d < n/d。但这会立即转换为d² < nd < √n
  3. 因此,无论哪种方式,每对除数都包含(至少)不超过√n的除数,因此,如果n是复合数,则其最小除数(除1之外)不超过√n

    因此,当我们到达√n时,我们可以停止审判部门:

    private static boolean checkMod( int num) {
        for (int i : primes){
            if (i*i > n){
                // We have not found a divisor less than √n, so it's a prime
                return true;
            }
            if( num % i == 0){
                return false;
            }
        }
        return true;
    }
    

    注意:这取决于按升序迭代的素数列表。如果语言无法保证,则必须使用不同的方法,通过ArrayList或类似的方式按索引进行迭代。

    在候选人的平方根处停止试验分区,对于100万以下的最大素数,999983,我们现在只需要将其除以1000以下的168个素数。这比以前少得多。在平方根处停止试验分区,并且只用素数除法,就像试验分区可能获得并且要求一样好

    2*n^1.5 / (3*(log n)²)
    
    对于n = 1000000来说,这是一个大约750的因素,不错,是吗?

    但这仍然不是很有效,找到n以下所有素数的最有效方法是筛子。简单实现是经典的Sieve of Eratosthenes。在O(n * log log n)运算中找到n以下的素数,并进行了一些增强(预先考虑了几个小素数的倍数),其复杂度可以简化为O(n)运算。一个具有更好渐近行为的相对较新的筛是Sieve of Atkin,它在O(n)运算中找到n的素数,或者在O(n)中增强消除一些小素数的倍数。 / log log n)操作。 Atkin的筛选实施起来更加复杂,因此Eratosthenes筛选的良好实施可能比天然的Atve筛选实施得更好。对于类似优化级别的实现,性能差异很小,除非限制变大(大于10 10 ;并且在实践中,Eratosthenes的筛子比Atkin的筛子更好地扩展并不罕见那,由于更好的内存访问模式)。所以我建议从Eratosthenes筛选开始,只有在优化方面努力表现不尽如人意,才能深入研究阿特金筛选。或者,如果您不想自己实现它,请找一个其他人已经认真调整过的好实现。

    我在an answer中进行了一些更详细的设置,设置略有不同,问题是找到了第n个素数。一些或多或少有效方法的实现与该答案相关联,特别是一个或两个可用的(虽然没有太多优化)Eratosthenes筛选的实现。

答案 1 :(得分:1)

我总是使用Eratosthenes筛子:

isPrime[100001] // - initially contains only '1' values (1,1,1 ... 1)
isPrime[0] = isPrime[1] = 0 // 0 and 1 are not prime numbers

primes.push(2); //first prime number. 2 is a special prime number because is the only even prime number.
for (i = 2; i * 2 <= 100000; i++) isPrime[i * 2] = 0 // remove all multiples of 2

for (i = 3; i <= 100000; i += 2) // check all odd numbers from 2 to 100000
    if (isPrime[i]) {
        primes.push(i); // add the new prime number to the solution
        for (j = 2; i * j <= 100000; j++) isPrime[i * j] = 0; // remove all i's multiples
    }

return primes

我希望你理解我的意见

答案 2 :(得分:0)

我理解一个素数是一个只能被自身整除的数字和数字1(没有余数)。见Wikipedia Article

话虽这么说,我在第二条评论中并没有很好地理解算法,但对你的算法的一个小改进是将你的for循环更改为:

for (int i = 5; i < 100000; i = i + 2) {
    if (checkMod(i)) {
        primes.add(i);
    }
}

这是基于这样的假设,即1,2和3都是素数,此后所有偶数都不是素数。这至少可以将你的算法减少一半。

答案 3 :(得分:0)

我想对本杰明·阿曼(Benjamin Oman)上面提到的0ne做一个稍微改进的版本, 这只是一个修改,以避免检查以数字'5'结尾的所有数字的素数,因为这些数字肯定不是素数,因为它们可以被5整除。

for (int i = 7;(i < 100000) && (!i%5==0); i = i + 2) {
    if (checkMod(i)) {
        primes.add(i);
    }
}

这是基于2,3,5是素数的假设。上述微小变化将减少5的所有因素并改善。

答案 4 :(得分:0)

@Daniel Fischer很好地解释了。

从他的解释中用C ++实现:

#include<iostream>

using namespace std;

long* getListOfPrimeNumbers (long total)
{
  long * primes;
  primes = new long[total];
  int count = 1;
  primes[0] = 2;
  primes[1] = 3;
  while (count < total)
  {
    long composite_number = primes[count] + 2;
    bool is_prime = false;
    while (is_prime == false)
    {
      is_prime = true;
      for (int i = 0; i <= count; i++)
      {
        long prime = primes[i];
        if (prime * prime > composite_number)
        {
          break;
        }
        if (composite_number % prime == 0)
        {
          is_prime = false;
          break;
      }
      }
      if (is_prime == true)
      {
        count++;
        primes[count] = composite_number;
      }
      else
      {
        composite_number += 2;
    }
  }
  }
  return primes;
}

int main()
{
  long * primes;
  int total = 10;
  primes = getListOfPrimeNumbers(total);
  for (int i = 0; i < total; i++){
    cout << primes[i] << "\n";
  }
  return 0;
}

答案 5 :(得分:0)

import array , math

print("enter a range to find prime numbers")

a= 0
b= 5000
c=0
x=0
k=1
g=[2]
l=0


for I in range( a , b):
    for k in g:
        x=x+1


        if k>2:
            if k > math . sqrt( I ):

                break

        if( I % k==0):

            c=c+1
            break
    if c==0:
        if I!=1:

            g . append( I )



    c=0    
print g



#this algorithm will take only 19600 iteration for a range from 1-5000,which is one of fastest algorithm according to me

答案 6 :(得分:0)

我发现数学家说“ 3之后的素数始终是6的倍数的一侧”。 它的5,7质数接近6。 11,13也更接近6 2。 17,19也是6 3。 21,23也是6 * 4。 我既写正常代码,又写了多达一百万条代码,我发现该算法也是正确且更快的。?


num=1000000
prime=[2,3]
def test(i):
    for j in prime:
        if(i%j==0):
            break
        if(j*j>i):
            prime.append(i)
            break
    return 0
for i in range (6,num,6):
    i=i-1
    test(i)
    i=i+2
    test(i)
    i=i-1
    
print(prime)