埃拉托斯特尼筛法

埃拉托斯特尼筛法（，），簡稱-{zh-cn:埃氏筛; zh-tw:埃氏篩; zh-hk:愛氏篩}-，是一种用來質數的筛法，得名於古希臘數學家埃拉托斯特尼。其基本步骤是從最小的質數2開始，將该質數的所有倍數標記成合數，而下一个尚未被标记的最小自然数3即是下一个質數。如此重复这一过程，将各个质数的倍数标记为合数并找出下一个质数，最终便可找出一定範圍內所有質數。

埃拉托斯特尼筛法可能在埃拉托斯特尼的时代之前就已经为人所知，并记载于另一位古希腊数学家尼科马库斯的《》中，尽管该著作中的这一筛法是从3开始，从奇数中依次筛去奇数的倍数，而非从自然数中筛去质数的倍数。

 运用与示例 

埃拉托斯特尼筛法通过不断地标记当前质数的所有倍数为合数，从而取得最小的未标记整数为下一个質數。不过，在实际使用此筛法寻找一个范围内的質數时，不需要检查范围内所有整数，也不需要对每个質數都标记其所有的倍数。
寻找以内的質數时，若找到了一个大于的质数，则剩余的所有尚未标记的数也都是質數。
证明：若这些尚未标记的数中有任意一个为合数，设之为，则必定是除1与自身以外的两个因数的乘积。但既然尚未被标记，则所有小于等于的数均不是的因数。故这两个因数必然都大于，则不可能在以内。
标记某一質數的倍数时，不需要每次皆从开始，而可直接从开始标记。
证明：所有较更小的的倍数必然拥有一个更小的质数为其因数，故在标记之前的质数的倍数时它们已经被标记过了。

若要找出25以内的所有质数，使用如上述改进过的埃拉托斯特尼筛法的具体过程如下：

列出2以後所有數：
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
记录質数2，由2=4开始划去2的倍数：
2 3  5  7  9  11  13  15  17  19  21  23  25
记录下一質数3，由3=9开始划去3的倍数：
2 3  5  7  11  13  17  19  23  25
记录下一質数5，由5=25开始划去5的倍数：
2 3  5  7  11  13  17  19  23  
下一質数为7，而7=49>25，故剩余所有未标记的数皆为質数：
2 3  5  7  11  13  17  19  23  

由此得到25內的質数为2，3，5，7，11，13，17，19，23。

以上的算法可用以下-{zh-cn:伪代码;zh-tw:虛擬碼;}-表示：

-{zh-cn:
 输入：整数n > 1

 设A为布尔值矩阵，下标是2至n的整数，
 初始时全部设成true。

  for i = 2, 3, 4, ..., 不超过：
   if A[i]为true：
     for j = i2, i2+i, i2+2i, i2+3i, ..., 不超过n：
       A[j] := false

 输出：使A[i]为true的所有i。;zh-tw:

 輸入：整數n > 1

 設A為布爾值陣列，指標是2至n的整數，
 初始時全部設成true。

  for i = 2, 3, 4, ..., 不超過：
   if A[i]為true：
     for j = i2, i2+i, i2+2i, i2+3i, ..., 不超過n：
       A[j] := false

 輸出：使A[i]為true的所有i。;}-

埃拉托斯特尼筛法的时间复杂度为；相比之下，若是通过对范围内每个整数进行试除法来找出范围内的质数，则其时间复杂度为。

代码
Python 3.6-3.10
def eratosthenes(n):
    is_prime = [True] * (n + 1)
    for i in range(2, int(n ** 0.5) + 1):
        if is_prime[i]:
            for j in range(i * i, n + 1, i):
                is_prime[j] = False
    return [x for x in range(2, n + 1) if is_prime[x]]
print(eratosthenes(120))

C語言
int prime[100005];
bool is_prime[1000005];

int eratosthenes(int n) {
    int p = 0;
    for (int i = 0; i <= n; i++) {
        is_prime[i] = true;
    }
    is_prime[0] = is_prime[1] = 0;
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) {
            prime[p++] = i;
            if (1ll * i * i <= n) {
                for (int j = i * i; j <= n; j += i) {
                    is_prime[j] = 0;
                }
            }
        }
    }
    return p;
}

C語言新版
#include <stdio.h>
#include <stdlib.h>

/* N: positive integer
   verbose: 1 -- print all prime numbers < N, 0 -- no print
   return total number of prime numbers < N. 
   return -1 when there is not enough memory.
*/
int eratosthenesSieve(unsigned long long int N, int verbose) {
  // prime numbers are positive, better to use largest unsiged integer
  unsigned long long int i, j, total; // total: number of prime numbers < N
  _Bool *a = malloc(sizeof(_Bool) * N);

  if (a == NULL) {
    printf("No enough memory.\n");
    return -1;
  }

  /* a[i] equals 1: i is prime number.
     a[i] equals 0: i is not prime number.
     From beginning, set i as prime number. Later filter out non-prime numbers
  */
  for (i = 2; i < N; i++) {
    a[i] = 1; 
  }

  // mark multiples(<N) of i as non-prime numbers
  for (i = 2; i < N; i++) {
    if (a[i]) { // a[i] is prime number at this point
      for (j = i; j < (N / i) + 1; j++) {
	/* mark all multiple of 2 * 2, 2 * 3, as non-prime numbers;
	   do the same for 3,4,5,... 2*3 is filter out when i is 2
	   so when i is 3, we only start at 3 * 3
	*/
	a[i * j] = 0;
      }
    }
  }

  // count total. print prime numbers < N if needed.
  total = 0;
  for (i = 2; i < N; i++) {
    if (a[i]) { // i is prime number
      if (verbose) {
	printf("%llu\n", i);
      }
      total += 1;
    }
  }

  return total;
}

int main() {
  unsigned long long int a1 = 0, a2 = 0, N = 10000000;

  a1 = eratosthenesSieve(N, 1); // print the prime numbers
  printf("Total of prime numbers less than %llu is : %llu\n", N, a1);

  a2 = eratosthenesSieve(N, 0); // not print the prime numbers
  printf("Total of prime numbers less than %llu is : %llu\n", N, a2);

  return 0;
}

C++
#include <vector>

auto eratosthenes(int upperbound) {
  std::vector<bool> flag(upperbound + 1, true);
  flag[0] = flag[1] = false; //exclude 0 and 1
  for (int i = 2; i * i <= upperbound; ++i) {
    if (flag[i]) {
      for (int j = i * i; j <= upperbound; j += i)
        flag[j] = false;
    }
  }
  return flag;
}

R
eratosthenes <- function(n) {
  if (n == 1) return(NULL)
  if (n == 2 | n == 3) return(2:n)
  numbers <- 2:n
  primes <- rep(TRUE, n-1)
  for (i in 2:floor(sqrt(n))) {
    if (primes[i-1]) {
      for (j in seq(i * i, n, i))
        primes[j-1] <- FALSE
    }
  }
  return(numbers[primes])
}

JavaScript
const countPrimes = function (n) {
  const isPrime = new Array(n).fill(true);

  for (let i = 2; i <= Math.sqrt(n); i++) {
    if (isPrime[i]) {
      for (let j = i * i; j <= n; j += i) {
        isPrime[j] = false;
      }
    }
  }

  let count = 0;
  for (let i = 2; i < n; i++) {
    if (isPrime[i]) {
      count++;
    }
  }

  return count;
};

参见

篩法
卢卡斯-莱默检验法
米勒-拉宾检验
试除法
费马素性检验
孪生素数
三胞胎素数
四胞胎素数
素数判定法则
表兄弟素数
六素数
X²+1素数
勒讓德篩法

参考文献

 拓展阅读 
Interactive animation (需要JavaScript) 
打印质数的各种算法 
筛法小结 (Eratosthenes/Euler)
欧拉函数线性筛法详解 （欧拉函数线性筛）
一般筛法求素数+快速线性筛法求素数(较好理解) 

Category:素性测试
Category:带有伪代码示例的条目

Category:算法