1. 程式人生 > >快速獲得指定數$n$之內的所有素數

快速獲得指定數$n$之內的所有素數

素數性質

在自然數列中,除1之外,若某個數字不可被分割,則該數字即為素數。標準的數學描述是在自然數列中,除1之外的數無法被1和它本身整除,則該數字為素數;反之可以被1和本身整除的數字稱為合數。

如果針對這樣的理解,我們常規的作法就是從2開始,在小於自身的範圍內的所有自然數都無未能整除自身數字。

第一個性質

其實所有數字都是一個性質,若存在兩個因子相乘 n=a×bn=a\times b 的情況,則兩因子一定分佈在n\sqrt{n}值的兩側或兩值均等於n\sqrt{n}

所以,我們只需要測試從2開始的自然數列,到被測試數值n\sqrt{n}即可。這種情況下,程式碼的效能得到提升。計算機所需時間代價也會變成O

(n)O(\sqrt{n})

第二個性質

即便如此,程式程式碼中還存在有另一個特性——合數重複判定。如果我們判斷某個數字能被2整除,自然不是素數,跳出迴圈即可。但是如果它即不能被2整除時,一定不能被2的任意倍數整除,當然,如果不能被3整除,它當然也不能3的任意倍數整除!

在實際的使用中,我們測試nn是否素數時,判斷過2不能整除nn,那麼4,6等均不能整除nn,但是我們從2測試到n\sqrt{n}的過程中,一直存在有合數的判斷。

其實用數學知識證明很容易的,假定待判定因子是m=a×bm= a\times b, 如果nmod  a

̸=0n\mod a \not= 0nmod  b̸=0n\mod b\not=0,那麼nmod  m̸=0n\mod m \not=0,所以如果我們測試過合數的兩個素因子aabb之後,完全沒有必要再測試合數mm

再換句話來說,我們只需要測試從2到n\sqrt{n}之間的所有素數是否整除nn就可以了!

這樣計算的時間代價比較複雜,它涉及到了n\sqrt{n}之內的素數分佈情況,在根據素密公式來說,這種演算法的時間代價是O(t(

n))O(t(\sqrt{n}))t(n)t(\sqrt{n})表示在n\sqrt{n}範圍內素數的個數,也叫素密公式。

素數列表實現

上文中的兩個性質介紹之後,我們要考慮如果程式設計的問題了。換句話來說,我們判斷nn是否為素數時,需要n\sqrt{n}之內的素數列表。那麼求素數列表時,顯然已求出的部分可以被正在求的數字做為基礎。這種情況有點象多米諾骨牌。

python語言實現

#!/usr/bin/python3

import math
#prime list
arr = [2]

def getPrimeList(n):
    for p in range(3,n,2):
        e = math.sqrt(p)
        for t in arr:
            if p%t==0:break
            if t>e:arr.append(p);break

#start
getPrimeList(1000)
print(arr)

C++ 語言實現

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

vector<int> PrimeList;
void GetPrimeList(int n)
{
    PrimeList.push_back(2);
    for(int p = 3;p<=n;p+=2){
        double tmp = sqrt(p);
        for(int &i:PrimeList){
            if(p&i==0) break;
            if(i>tmp){PrimeList.push_back(p);break;}
}

int main()
{
    PrimeList.clear();
    GetPrimeList(1000);
    for(int &i : PrimeList) cout << i << ';';
    cout << endl;
}

Csharp語言實現

static List<int> _PrimeList;
static void GetPrimeList(int n)
{
	for(int p = 3;i<=n;i+=2){
	    double tmp = Math.Sqrt(p);
	    foreach(int i in _PrimeList){
	        if(p%i == 0)break;
	        if(i>tmp){_PrimeList.Add(p);break;}
	    }
	}
}
#entry
static void Main(string[] args)
{
	_PrimeList = new List<int>();
	_primeList.Add(2);
	GetPrimeList(1000);
	Console.Write(string.Join(",",_PrimeList));
}