快速获得指定数$n$之内的所有素数

素数性质

在自然数列中,除1之外,若某个数字不可被分割,则该数字即为素数。标准的数学描述是在自然数列中,除1之外的数无法被1和它本身整除,则该数字为素数;反之可以被除1和本身之外整除的数字称为合数。

如果针对这样的理解,我们常规的作法就是从2开始,在小于自身的范围内的所有自然数都无未能整除自身数字。

第一个性质

其实所有数字都是一个性质,若存在两个因子相乘 n = a × b n=a\times b n=a×b 的情况,则两因子一定分布在 n \sqrt{n} n 值的两侧或两值均等于 n \sqrt{n} n

所以,我们只需要测试从2开始的自然数列,到被测试数值 n \sqrt{n} n 即可。这种情况下,代码的性能得到提升。计算机所需时间代价也会变成 O ( n ) O(\sqrt{n}) O(n )

第二个性质

即便如此,程序代码中还存在有另一个特性——合数重复判定。如果我们判断某个数字能被2整除,自然不是素数,跳出循环即可。但是如果它即不能被2整除时,一定不能被2的任意倍数整除,当然,如果不能被3整除,它当然也不能3的任意倍数整除!

在实际的使用中,我们测试 n n n是否素数时,判断过2不能整除 n n n,那么4,6等均不能整除 n n n,但是我们从2测试到 n \sqrt{n} n 的过程中,一直存在有合数的判断。

其实用数学知识证明很容易的,假定待判定因子是 m = a × b m= a\times b m=a×b, 如果 n m o d    a ̸ = 0 n\mod a \not= 0 nmoda̸=0 n m o d    b ̸ = 0 n\mod b\not=0 nmodb̸=0,那么 n m o d    m ̸ = 0 n\mod m \not=0 nmodm̸=0,所以如果我们测试过合数的两个素因子 a a a b b b之后,完全没有必要再测试合数 m m m

再换句话来说,我们只需要测试从2到 n \sqrt{n} n 之间的所有素数是否整除 n n n就可以了!

这样计算的时间代价比较复杂,它涉及到了 n \sqrt{n} n 之内的素数分布情况,在根据素密公式来说,这种算法的时间代价是 O ( t ( n ) ) O(t(\sqrt{n})) O(t(n )) t ( n ) t(\sqrt{n}) t(n )表示在 n \sqrt{n} n 范围内素数的个数,也叫素密公式。

素数列表实现

上文中的两个性质介绍之后,我们要考虑如果编程的问题了。换句话来说,我们判断 n n n是否为素数时,需要 n \sqrt{n} 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));
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值