跳转到内容

埃拉托斯特尼筛法:修订间差异

维基百科,自由的百科全书
删除的内容 添加的内容
内容扩充 增加参考来源
标签移除维护性模板
第1行: 第1行:
{{multiple issues|
{{cleanup-jargon|time=2018-02-21T02:36:43+00:00}}
{{inappropriate tone|time=2018-02-21T02:36:43+00:00}}
}}
{{NoteTA
{{NoteTA
|G1=Math
|G1=Math
}}
}}


'''埃拉托斯特尼筛法'''({{lang-el|κόσκινον Ἐρατοσθένους}},{{lang-en|sieve of Eratosthenes}}),簡稱'''-{zh-cn:埃氏筛; zh-tw:埃氏篩; zh-hk:愛氏篩}-''',也称'''素数筛''',是簡單且历史悠久的[[筛法]],用來找出一定範圍內所有[[質數]]
'''埃拉托斯特尼筛法'''({{lang-grc|κόσκινον Ἐρατοσθένους}},{{lang-en|sieve of Eratosthenes}}),簡稱'''-{zh-cn:埃氏筛; zh-tw:埃氏篩; zh-hk:愛氏篩}-''',是一种用來{{tsl|en|Generating primes|質數生成|生成}}[[質數]]的[[筛法]],得名於[[古希臘數學|古希臘數學家]][[埃拉托斯特尼]]。其基本步骤是從最小的質數2開始,將该質數的所有倍數標記成[[合數]],而下一个尚未被标记的最小自然数3即是下一个質數。如此重复这一过程,将各个质数的倍数标记为合数并找出下一个质数,最终便可找出一定範圍內所有質數。


埃拉托斯特尼筛法可能在埃拉托斯特尼的时代之前就已经为人所知<ref name="am">{{cite book |author1=Stefan Hougardy |author2=Jens Vygen |title=Algorithmic Mathematics |date=2016 |publisher=Springer International Publishing Switzerland |location=Cham |isbn=978-3-319-39558-6 |url=https://link.springer.com/book/10.1007/978-3-319-39558-6}}</ref>{{rp|14}},并记载于另一位古希腊数学家[[尼科马库斯]]的《{{tsl|en|Introduction to Arithmetic|算术概论}}》中,尽管该著作中的这一筛法是从3开始,从[[奇数]]中依次筛去奇数的倍数,而非从自然数中筛去质数的倍数<ref>{{cite book |author1=Jean-Luc Chabert |title=A History of Algorithms: From the Pebble to the Microchip |date=1999 |publisher=Springer-Verlag |location=Berlin, Heidelberg |isbn=978-3-642-18192-4 |url=https://link.springer.com/book/10.1007/978-3-642-18192-4}}</ref>{{rp|242-243}}。
原理是從2開始,將每個[[質數]]的各倍數標記成[[合數]]。一個質數的各個倍數,是一個差為此質數本身的[[等差数列|等差數列]]。此為這個篩法和[[試除法]]不同的關鍵之處,後者是以質數來測試能否整除每個待測數。


{{Image frame|width=350|content=[[File:Sieve_of_Eratosthenes_animation.gif|350px]]|align=right|caption=使用埃拉托斯特尼筛法找出120以内的所有質數。由于11{{sup|2}}=121>120,当11成为最小的未标记整数时,尚未标记的所有数皆可确认为質數。请注意到在标记时直接从每个质数的[[平方]]开始。}}
質數篩是列出所有小質數的有效方法,得名於[[古希臘數學|古希臘數學家]][[埃拉托斯特尼]],並且描述在另一位古希臘數學家[[尼科馬庫斯]]所著的《算術入門》中。<ref>[[尼科馬庫斯|Nicomachus]], ''Introduction to Arithmetic'', I, 13. [http://www.archive.org/stream/nicomachigerasen00nicouoft#page/29/mode/1up]</ref>


== 运用与示例 ==
作為現代篩法基礎的[[勒讓德篩法]]是埃拉托斯特尼篩法的簡單推廣,有些文獻會將勒讓德篩法稱作埃拉托斯特尼篩法。


埃拉托斯特尼筛法通过不断地标记当前质数的所有倍数为合数,从而取得最小的未标记整数为下一个質數。不过,在实际使用此筛法寻找一个范围内的質數时,不需要检查范围内所有整数,也不需要对每个質數都标记其所有的倍数。
==算式==
#寻找<math>N</math>以内的質數时,若找到了一个大于<math>\sqrt{N}</math>的质数,则剩余的所有尚未标记的数也都是質數。
定出要筛数值的范围n,找出{{根號|n|use math=yes}}以内的[[素数|質數]]<math>p_{1},p_{2},\dots,p_{k}</math>。先用2去筛,把2留下,把2的倍数剔除掉;再用下個質數3筛,把3留下,把3的倍数剔除掉;接下去用下個質數5筛,把5留下,把5的倍数剔除掉,直至夠為止。
#:'''证明''':若这些尚未标记的数中有任意一个为合数,设之为<math>m</math>,则<math>m</math>必定是除1与自身以外的两个[[因数]]的乘积。但既然<math>m</math>尚未被标记,则所有小于等于<math>\sqrt{N}</math>的数均不是<math>m</math>的因数。故这两个因数必然都大于<math>\sqrt{N}</math>,则<math>m</math>不可能在<math>N</math>以内<ref>{{cite book |author1=George M. Phillips |title=Mathematics Is Not a Spectator Sport |year=2005 |publisher=Springer-Verlag |location=New York |isbn=978-0-387-28697-6 |url=https://link.springer.com/book/10.1007/0-387-28697-7}}</ref>{{rp|103-104}}<ref>{{cite book |author1=G. H. Hardy |authorlink1=戈弗雷·哈罗德·哈代 |author2=E. M. Wright |authorlink2=爱德华·梅特兰·赖特 |title=An Introduction to the Theory of Numbers (Fourth Edition) |date=1960 |publisher=Clarendon Press |location=Oxford |isbn=978-0-19-853310-8}}</ref>{{rp|4}}。
#标记某一質數<math>p</math>的倍数时,不需要每次皆从<math>2 p, 3 p, \ldots</math>开始,而可直接从<math>p^2</math>开始标记。
#:'''证明''':所有较<math>p^2</math>更小的<math>p</math>的倍数必然拥有一个更小的质数为其因数,故在标记之前的质数的倍数时它们已经被标记过了<ref name="tgse">{{cite journal |author1=Melissa E. O'Neill |title=The Genuine Sieve of Eratosthenes |journal=Journal of Functional Programming |date=2009 |volume=19 |issue=1 |pages=95-106 |doi=10.1017/S0956796808007004 |url=https://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf}}</ref>。


若要找出25以内的所有质数,使用如上述改进过的埃拉托斯特尼筛法的具体过程如下:
===步驟===
[[File:Sieve_of_Eratosthenes_animation.gif|right|350px|埃拉托斯特尼筛法]]
详细列出算法如下:


#列出2以後所有數:
#列出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 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{{sup|2}}=4开始划去2的倍数:
#标記第一个質数2:
#*<span style="font-size:large;">2</span> 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
#:<span style="font-size:x-large;">2</span> 3 {{gray|<s> 4 </s>}} 5 {{gray|<s> 6 </s>}} 7 {{gray|<s> 8 </s>}} 9 {{gray|<s>10</s>}} 11 {{gray|<s>12</s>}} 13 {{gray|<s>14</s>}} 15 {{gray|<s>16</s>}} 17 {{gray|<s>18</s>}} 19 {{gray|<s>20</s>}} 21 {{gray|<s>22</s>}} 23 {{gray|<s>24</s>}} 25
#用红色标記2的倍数:
#记录下一質数3,由3{{sup|2}}=9开始划去3的倍数:
#*<span style="font-size:large;">2</span> 3 <span style="font-size:x-small; color:red;">4</span> 5 <span style="font-size:x-small; color:red;">6</span> 7 <span style="font-size:x-small; color:red;">8</span> 9 <span style="font-size:x-small; color:red;">10</span> 11 <span style="font-size:x-small; color:red;">12</span> 13 <span style="font-size:x-small; color:red;">14</span> 15 <span style="font-size:x-small; color:red;">16</span> 17 <span style="font-size:x-small; color:red;">18</span> 19 <span style="font-size:x-small; color:red;">20</span> 21 <span style="font-size:x-small; color:red;">22</span> 23 <span style="font-size:x-small; color:red;">24</span> 25
#:<span style="font-size:x-large;">2</span> <span style="font-size:x-large;">3</span> {{gray|<s> 4 </s>}} 5 {{gray|<s> 6 </s>}} 7 {{gray|<s> 8 </s>}}{{gray|<s> 9 </s>}}{{gray|<s>10</s>}} 11 {{gray|<s>12</s>}} 13 {{gray|<s>14 </s>}}{{gray|<s>15 </s>}}{{gray|<s>16</s>}} 17 {{gray|<s>18</s>}} 19 {{gray|<s>20 </s>}}{{gray|<s>21 </s>}}{{gray|<s>22</s>}} 23 {{gray|<s>24</s>}} 25
#记录下一質数5,由5{{sup|2}}=25开始划去5的倍数:
#如果最大数不大於最後一個標出的質數的平方,那么剩下的所有的数都是質数,否则回到第二步。
#:<span style="font-size:x-large;">2</span> <span style="font-size:x-large;">3</span> {{gray|<s> 4 </s>}} <span style="font-size:x-large;">5</span> {{gray|<s> 6 </s>}} 7 {{gray|<s> 8 </s>}}{{gray|<s> 9 </s>}}{{gray|<s>10</s>}} 11 {{gray|<s>12</s>}} 13 {{gray|<s>14 </s>}}{{gray|<s>15 </s>}}{{gray|<s>16</s>}} 17 {{gray|<s>18</s>}} 19 {{gray|<s>20 </s>}}{{gray|<s>21 </s>}}{{gray|<s>22</s>}} 23 {{gray|<s>24</s>}} {{gray|<s> 25 </s>}}
----
#下一質数为7,而7{{sup|2}}=49>25,故剩余所有未标记的数皆为質数:
#本例中,25大于2的平方,返回第二步:
#:<span style="font-size:x-large;">2</span> <span style="font-size:x-large;">3</span> {{gray|<s> 4 </s>}} <span style="font-size:x-large;">5</span> {{gray|<s> 6 </s>}} <span style="font-size:x-large;">7</span> {{gray|<s> 8 </s>}}{{gray|<s> 9 </s>}}{{gray|<s>10</s>}} <span style="font-size:x-large;">11</span> {{gray|<s>12</s>}} <span style="font-size:x-large;">13</span> {{gray|<s>14 </s>}}{{gray|<s>15 </s>}}{{gray|<s>16</s>}} <span style="font-size:x-large;">17</span> {{gray|<s>18</s>}} <span style="font-size:x-large;">19</span> {{gray|<s>20 </s>}}{{gray|<s>21 </s>}}{{gray|<s>22</s>}} <span style="font-size:x-large;">23</span> {{gray|<s>24</s>}} {{gray|<s> 25 </s>}}
#2之後第一个質数是3,用藍色標記3的倍数:
#*<span style="font-size:x-large;">2</span> <span style="font-size:large;">3</span> 4 5 <span style="font-size:x-small; color:blue;">6</span> 7 8 <span style="font-size:x-small; color:blue;">9</span> 10 11 <span style="font-size:x-small; color:blue;">12</span> 13 14 <span style="font-size:x-small; color:blue;">15</span> 16 17 <span style="font-size:x-small; color:blue;">18</span> 19 20 <span style="font-size:x-small; color:blue;">21</span> 22 23 <span style="font-size:x-small; color:blue;">24</span> 25

#得到的質数是2,3。
#25仍大于3的平方,再次返回第二步:
#3之後第一个質数是5,用綠色標記5的倍数:
#*<span style="font-size:xx-large;">2</span> <span style="font-size:x-large;">3</span> <span style="font-size:x-small; color:red;">4</span> <span style="font-size:large;">5</span> <span style="font-size:x-small; color:red;">6</span> 7 <span style="font-size:x-small; color:red;">8</span> <span style="font-size:x-small; color:red;">9</span> <span style="font-size:x-small; color:green;">10</span> 11 <span style="font-size:x-small; color:red;">12</span> 13 <span style="font-size:x-small; color:red;">14</span> <span style="font-size:x-small; color:green;">15</span> <span style="font-size:x-small; color:red;">16</span> 17 <span style="font-size:x-small; color:red;">18</span> 19 <span style="font-size:x-small; color:green;">20</span> <span style="font-size:x-small; color:red;">21</span> <span style="font-size:x-small; color:red;">22</span> 23 <span style="font-size:x-small; color:red;">24</span> <span style="font-size:x-small; color:green;">25</span>
#得到的質数是2,3,5。
#25是5的平方,篩選完畢。

结论:去掉红色及綠色的数,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:伪代码;zh-tw:虛擬碼;}-]]表示:


-{zh-cn:
-{zh-cn:
第72行: 第59行:
'''輸出''':使''A''[''i'']為'''true'''的所有''i''。;}-
'''輸出''':使''A''[''i'']為'''true'''的所有''i''。;}-


埃拉托斯特尼筛法的[[时间复杂度]]为<math>O(n\log (\log n))</math>;相比之下,若是通过对范围内每个整数进行[[试除法]]来找出范围内的质数,则其时间复杂度为<math>O(n\sqrt {n})</math><ref name="am" />{{rp|13-14}}<ref name="tgse" />。
以上演算法可以得到小於等於{{mvar|n}}的所有[[質數|質數]],它的複雜度是{{math|O(''n'' log log ''n'')}}。


==程式码==
==程式码==
第259行: 第246行:


==参考文献==
==参考文献==
<references />{{refbegin}}
<references />
* ''{{lang|el|Κοσκινον Ερατοσθενους}} or, The Sieve of Eratosthenes. Being an Account of His Method of Finding All the Prime Numbers'', by the Rev. Samuel Horsley, F. R. S., Philosophical Transactions (1683-1775), Vol. 62. (1772), pp. 327-347.
{{refend}}


== 拓展阅读 ==
== 拓展阅读 ==

2024年1月5日 (五) 03:50的版本

埃拉托斯特尼筛法古希臘語κόσκινον Ἐρατοσθένους,英語:sieve of Eratosthenes),簡稱埃氏筛,是一种用來生成英语Generating primes質數筛法,得名於古希臘數學家埃拉托斯特尼。其基本步骤是從最小的質數2開始,將该質數的所有倍數標記成合數,而下一个尚未被标记的最小自然数3即是下一个質數。如此重复这一过程,将各个质数的倍数标记为合数并找出下一个质数,最终便可找出一定範圍內所有質數。

埃拉托斯特尼筛法可能在埃拉托斯特尼的时代之前就已经为人所知[1]:14,并记载于另一位古希腊数学家尼科马库斯的《算术概论英语Introduction to Arithmetic》中,尽管该著作中的这一筛法是从3开始,从奇数中依次筛去奇数的倍数,而非从自然数中筛去质数的倍数[2]:242-243

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

运用与示例

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

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

若要找出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。

以上的算法可用以下伪代码表示:

输入:整数n > 1
 
设A为布尔值矩阵,下标是2至n的整数,
初始时全部设成true。
 
 for i = 2, 3, 4, ..., 不超过if A[i]为truefor j = i2, i2+i, i2+2i, i2+3i, ..., 不超过nA[j] := false
 
输出:使A[i]为true的所有i

埃拉托斯特尼筛法的时间复杂度;相比之下,若是通过对范围内每个整数进行试除法来找出范围内的质数,则其时间复杂度为[1]:13-14[5]

程式码

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;
};

参见

参考文献

  1. ^ 1.0 1.1 Stefan Hougardy; Jens Vygen. Algorithmic Mathematics. Cham: Springer International Publishing Switzerland. 2016. ISBN 978-3-319-39558-6. 
  2. ^ Jean-Luc Chabert. A History of Algorithms: From the Pebble to the Microchip. Berlin, Heidelberg: Springer-Verlag. 1999. ISBN 978-3-642-18192-4. 
  3. ^ George M. Phillips. Mathematics Is Not a Spectator Sport. New York: Springer-Verlag. 2005. ISBN 978-0-387-28697-6. 
  4. ^ G. H. Hardy; E. M. Wright. An Introduction to the Theory of Numbers (Fourth Edition). Oxford: Clarendon Press. 1960. ISBN 978-0-19-853310-8. 
  5. ^ 5.0 5.1 Melissa E. O'Neill. The Genuine Sieve of Eratosthenes (PDF). Journal of Functional Programming. 2009, 19 (1): 95–106. doi:10.1017/S0956796808007004. 

拓展阅读