使用埃拉托色尼筛法生成 k 个素数

generating k prime numbers using Sieve of Eratosthenes

看了几个实现发现,想知道为什么从k = m * m开始迭代是安全的?谢谢

http://www.algolist.net/Algorithms/Number_theoretic/Sieve_of_Eratosthenes

public void runEratosthenesSieve(int upperBound) {
      int upperBoundSquareRoot = (int) Math.sqrt(upperBound);
      boolean[] isComposite = new boolean[upperBound + 1];
      for (int m = 2; m <= upperBoundSquareRoot; m++) {
            if (!isComposite[m]) {
                  System.out.print(m + " ");
                  for (int k = m * m; k <= upperBound; k += m)
                        isComposite[k] = true;
            }
      }
      for (int m = upperBoundSquareRoot; m <= upperBound; m++)
            if (!isComposite[m])
                  System.out.print(m + " ");
}

每个小于 m*m 且 m 是其因数的合数,例如。 m*n,具有比 m 更小的因子,例如。 n,我们已经将其标记为复合。

这适用于质数或合数n,对于质数n,我们在m=n的循环中设置。

对于合数 n:我们知道任何大于 1 的整数都可以表示为质因数的乘积。其中一个质因数是 n 的最小质因数,我们称之为 s。由于 s 是 n 的质因数,对于某些 r,我们可以将 n 表示为 s*r。这也意味着 m*n 是 m*s*r。当 n < m 和 s < n 时,s < m。我们知道 r 没有小于 s 的质因数,因为它是这样定义的。所以s一定是m*s*r的最小质因数,所以我们在m=s的循环中设置它的iscomposite标志

让我们取一个数字并分解它:例如。 120

  • 1 x 120
  • 2 x 60
  • 3 x 40
  • 4 x 30
  • 5 x 24
  • 6 x 20
  • 8 x 15
  • 10 x 12

现在,一个观察:sqrt(120) = 11(发言)

现在,下一次观察,each of the above factors have one thing in common, ie. one of the factors is less than 11 and other is greater than 11

现在分解 36:

  • 1 x 36
  • 2 x 18
  • 3 x 12
  • 4 x 9
  • 6 x 6

和 sqrt(36) = 6。我们可以再次进行类似的观察,即每个因子都有一个小于 6 的数和另一个大于 6 的数,除了 6 x 6,因为 36 是一个正方形.

所以,我们可以很容易地推导出:

For any number, if it is not a prime number, we can always find (at least) one of its factor, if we go to its square root.

因此,为了降低复杂度,我们需要计算范围内每个数字的平方根,因此,sqrt(upperBound) 足以用于外循环。那是因为,如果任何数字到那时还没有被标记为合数,那将永远不会是合数,因为我们已经考虑了所有可能的除数。

编辑:

此外,这个 sieve 的实现不是 most optimized 可以的。不是在渐近复杂性方面,而是你可以做一些事情来减少一些操作。我将在 C++ 中添加我的 sieve 实现,它计算所有素数直到 MAX。

#define MAX 1000000
#define I int
#define FOR(i,a,b) for(i=a;i<b;i++)
I p[MAX]={1,1,0};            //global declaration
I prime[MAX/10]={2};         //global declaration
void sieve()
{
    I i,j,k=1;
    for(i=3;i*i<=MAX;i+=2)
    {
        if(p[i])
            continue;
        for(j=i*i;j<MAX;j+=2*i)
            p[j]=1;
    }
    for(i = 3; i < MAX; i+=2)
    {
        if(!p[i])
            prime[k++]=i;
    }
    return;
}