本页使用了标题或全文手工转换

埃拉托斯特尼筛法

维基百科,自由的百科全书
跳到导航 跳到搜索

埃拉托斯特尼筛法希臘語κόσκινον Ἐρατοσθένους,英語:sieve of Eratosthenes ),簡稱埃氏筛,也称素数筛。这是一種簡單且历史悠久的筛法,用來找出一定範圍內所有的質數

所使用的原理是從2開始,將每個質數的各個倍數,標記成合數。一個質數的各個倍數,是一個差為此質數本身的等差數列。此為這個篩法和試除法不同的關鍵之處,後者是以質數來測試每個待測數能否被整除。

埃拉托斯特尼篩法是列出所有小質數最有效的方法之一,其名字來自於古希臘數學家埃拉托斯特尼,並且被描述在另一位古希臘數學家尼科馬庫斯所著的《算術入門》中。[1]

算式[编辑]

给出要筛数值的范围n,找出以内的素数。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一個質數,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一個質數5筛,把5留下,把5的倍数剔除掉;不斷重複下去......。

步驟[编辑]

埃拉托斯特尼筛法

详细列出算法如下:

  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,序列变成:
    • 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. 将剩下序列中,劃摽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
  4. 如果现在这个序列中最大数小于等于最後一個標出的質數的平方,那么剩下的序列中所有的数都是質数,否则回到第二步。

  1. 本例中,因为25大于2的平方,我们返回第二步:
  2. 剩下的序列中第一个質数是3,将主序列中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
  1. 我们得到的質数有:2,3
  2. 25仍然大于3的平方,所以我们还要返回第二步:
  3. 现在序列中第一个質数是5,同样将序列中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
  4. 我们得到的質数有:2, 3, 5 。
  5. 因为25等于5的平方,結束循环

结论:去掉红色的数字,2到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

以上演算法可以得到小於等於n的所有素数,它的複雜度是O(n log log n)

程式代码[编辑]

Python 3.6[编辑]

def eratosthenes(n):
    IsPrime = [True] * (n + 1)
    for i in range(2, int(n ** 0.5) + 1):
        if IsPrime[i]:
            for j in range(i * i, n + 1, i):
                IsPrime[j] = False
    return [x for x in range(2, n + 1) if IsPrime[x]]
if __name__ == "__main__":
    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 programming language new version

#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 * 2, n, i))
        primes[j-1] <- FALSE
    }
  }
  return(numbers[primes])
}

JavaScript[编辑]

var countPrimes = function(n) {
    let count = 0;
    let signs = new Uint8Array(n);

    for (let i = 2; i <= Math.sqrt(n); i++) {
        if (!signs[i - 1]) {
            count++;

            for (let j = i * i; j <= n; j += i) {
                signs[j - 1] = true;
            }
        }
    }
    return count;
};

参见[编辑]

参考文献[编辑]

  1. ^ Nicomachus, Introduction to Arithmetic, I, 13. [1]
  • Κοσκινον Ερατοσθενους 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.

拓展阅读[编辑]