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

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

使用埃拉托斯特尼筛法找出120以内的所有質數。由于112=121>120，当11成为最小的未标记整数时，尚未标记的所有数皆可确认为質數。请注意到在标记时直接从每个质数的平方开始。

运用与示例
-----

埃拉托斯特尼筛法通过不断地标记当前质数的所有倍数为合数，从而取得最小的未标记整数为下一个質數。不过，在实际使用此筛法寻找一个范围内的質數时，不需要检查范围内所有整数，也不需要对每个質數都标记其所有的倍数。

1. 寻找N以内的質數时，若找到了一个大于\sqrt{N}的质数，则剩余的所有尚未标记的数也都是質數。
**证明**：若这些尚未标记的数中有任意一个为合数，设之为m，则m必定是除1与自身以外的两个因数的乘积。但既然m尚未被标记，则所有小于等于\sqrt{N}的数均不是m的因数。故这两个因数必然都大于\sqrt{N}，则m不可能在N以内。
2. 标记某一質數p的倍数时，不需要每次皆从{\displaystyle 2p,3p,\ldots }开始，而可直接从p^2开始标记。
**证明**：所有较p^2更小的p的倍数必然拥有一个更小的质数为其因数，故在标记之前的质数的倍数时它们已经被标记过了。

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

1. 列出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，由22=4开始划去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
3. 记录下一質数3，由32=9开始划去3的倍数：
2 3  ~~4~~  5  ~~6~~  7  ~~8~~  ~~9~~ ~~10~~ 11 ~~12~~ 13 ~~14~~ ~~15~~ ~~16~~ 17 ~~18~~ 19 ~~20~~ ~~21~~ ~~22~~ 23 ~~24~~ 25
4. 记录下一質数5，由52=25开始划去5的倍数：
2 3  ~~4~~  5  ~~6~~  7  ~~8~~  ~~9~~ ~~10~~ 11 ~~12~~ 13 ~~14~~ ~~15~~ ~~16~~ 17 ~~18~~ 19 ~~20~~ ~~21~~ ~~22~~ 23 ~~24~~  ~~25~~
5. 下一質数为7，而72=49>25，故剩余所有未标记的数皆为質数：
2 3  ~~4~~  5  ~~6~~  7  ~~8~~  ~~9~~ ~~10~~ 11 ~~12~~ 13 ~~14~~ ~~15~~ ~~16~~ 17 ~~18~~ 19 ~~20~~ ~~21~~ ~~22~~ 23 ~~24~~  ~~25~~

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

以上的算法可用以下表示：

-{zh-cn:

```
**输入**：整数*n* > 1
 
设*A*为布尔值矩阵，下标是2至*n*的整数，
初始时全部设成**true**。
 
 **for** *i* = 2, 3, 4, ... 不超过{\displaystyle {\sqrt {n}}}：
  **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, ... 不超過{\displaystyle {\sqrt {n}}}：
  **if** *A*[*i*]為**true**：
    **for** *j* = *i2*, *i2+i*, *i2+2i*, *i2+3i*, ... 不超過*n*：
      *A*[*j*] := **false**
 
**輸出**：使*A*[*i*]為**true**的所有*i*。;}-
```

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

程式码
---

### 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素数
* 勒讓德篩法
* 普理查篩法（英语：）
* 阿特金篩法（英语：）
* 孫達蘭篩法（英语：）

参考文献
----

1. 1 2  Stefan Hougardy; Jens Vygen.. Cham: Springer International Publishing Switzerland. 2016. ISBN 978-3-319-39558-6.
2. ↑  Jean-Luc Chabert.. Berlin, Heidelberg: Springer-Verlag. 1999. ISBN 978-3-642-18192-4.
3. ↑  George M. Phillips.. New York: Springer-Verlag. 2005. ISBN 978-0-387-28697-6.
4. ↑  G. H. Hardy; E. M. Wright.. Oxford: Clarendon Press. 1960. ISBN 978-0-19-853310-8.
5. 1 2  Melissa E. O'Neill.  (PDF). Journal of Functional Programming. 2009, **19** (1): 95–106. doi:10.1017/S0956796808007004.

拓展阅读
----

* Interactive animation (需要JavaScript) （页面存档备份，存于）
* 打印质数的各种算法 （页面存档备份，存于）
* 筛法小结 (Eratosthenes/Euler)
* 欧拉函数线性筛法详解 （页面存档备份，存于）（欧拉函数线性筛）
* 一般筛法求素数+快速线性筛法求素数(较好理解) （页面存档备份，存于）

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 

| * 
* 论
* 编
数论算法 |
| --- |
|  |
| 素数测试 | 
* AKS
* APR（英语：）
* Baillie–PSW（英语：）
* 椭圆曲线（英语：）
* Pocklington（英语：）
* 费马
* 卢卡斯（英语：）
* *卢卡斯-莱默*
* *Lucas–Lehmer–Riesel（英语：）*
* *普罗斯*
* *Pépin（英语：）*
* 二次Frobenius（英语：）
* Solovay–Strassen（英语：）
* 米勒-拉宾

 |
|  |
| 質數生成（英语：） | 
* 阿特金筛法（英语：）
* 埃拉托斯特尼筛法
* Pritchard筛法（英语：）
* Sundaram筛法（英语：）
* 輪式因數分解法（英语：）

 |
|  |
| 整数分解 | 
* 連分數分解 (CFRAC)（英语：）
* Dixon's（英语：）
* Lenstra橢圓曲線 (ECM)（英语：）
* 欧拉因式分解法（英语：）
* 波拉德ρ算法（英语：）
* *p* − 1（英语：）
* *p* + 1（英语：）
* 二次篩選法
* 普通数域筛选法
* *特殊數域篩選法 (SNFS)（英语：）*
* 有理筛选法
* 费马因式分解法（英语：）
* Shanks二次形式（英语：）
* 试除法
* 秀爾演算法

 |
|  |
| 乘法算法 | 
* 古埃及乘算（英语：）
* 長乘法
* 卡拉楚巴算法
* 图姆-库克算法
* 頌哈吉-施特拉森演算法
* 富尔算法（英语：）

 |
|  |
| 歐幾里德除法除法算法 | 
* 二進制（英语：）
* 倍塊法（英语：）
* Fourier（英语：）
* Goldschmidt（英语：）
* Newton-Raphson（英语：）
* 長除法
* 短除法
* SRT

 |
|  |
| 离散对数 | 
* 大步小步算法
* 波拉德ρ算法
* Pollard kangaroo（英语：）
* Pohlig–Hellman（英语：）
* Index calculus（英语：）
* Function field sieve（英语：）

 |
|  |
| 最大公因數 | 
* 二进制最大公因数算法（英语：）
* 輾轉相除法
* 扩展欧几里得算法
* Lehmer's（英语：）

 |
|  |
| 二次剩余 | 
* Cipolla（英语：）
* Pocklington's（英语：）
* Tonelli–Shanks（英语：）
* Berlekamp（英语：）
* Kunerth（英语：）

 |
|  |
| 其他算法 | 
* Chakravala（英语：）
* Cornacchia（英语：）
* 整數關係（英语：）（LLL（英语：）；KZ（英语：））
* 平方求冪
* 整数平方根
* 模幂运算
* 蒙哥马利算法
* Schoof（英语：）
* 特拉亨伯格系統（英语：）

 |
|  |
| 
* *斜体*表示该算法只适用于特殊形式的数字

 |

 |