素数判定

来源:互联网 发布:js获取当前显示器宽度 编辑:程序博客网 时间:2024/04/28 21:39

内容包括:

1.常规素数判定;

2.素数打表;

3.Miller-Rabin算法;

1.常规素数判定

素数判定的比较简洁版 比较省事 较优化

  bool isprime(int n)  {      if(n==2)return 1;      if(n%2==0) return 0;      int l=sqrt(n+1);      for(int i=3;i<=l;i+=2)        if(n%i==0)return 0;      return 1;  }


2.素数打表

对于素数询问次数较多 或询问区间内素数个数 可以采用打表

http://blog.csdn.net/niushuai666/article/details/6973134/

参考以上文章 学习了一种比较高效的打表

bool visit[10100000];int prime[10000000];int init_prim(int n){    memset(visit, true, sizeof(visit));    int num = 0;    for (int i = 2; i <= n; ++i)    {        if (visit[i] == true)        {            num++;            prime[num] = i;        }        for (int j = 1; ((j <= num) && (i * prime[j] <= n));  ++j)        {            visit[i * prime[j]] = false;            if (i % prime[j] == 0) break; //点睛之笔        }    }    return num;//返回质数

 prime可以直接输出所以的素数 可以用visit 快速访问一个数是否是素数

对于if (i % prime[j] == 0) break;这句 极大的缩短了时间 

以i=4举例 在执行visit[8]=0;后 跳出 而没有访问 12 把12留着i=6时 访问 减少了重复访问 使时间复杂度几乎为线性

3.Miller-Rabin算法

用于大数的高效判定素数算法 基于费马小定理的算法 是一种很稳定的不稳定算法 说不稳定是 因为算法判定素数是概率的

稳定是由于这种概率大于99.9% 所以就可以用 而且在工业中也是使用这种方法来判定

首先说一下费马小定理


代码借鉴一下文章

http://www.cnblogs.com/ziyi--caolu/p/3581345.html

typedef long long LL;
LL n,m;//****************************************************************// Miller_Rabin 算法进行素数测试//速度快,而且可以判断 <2^63的数//****************************************************************const int S=20;//随机算法判定次数,S越大,判错概率越小LL mult_mod(LL a,LL b,LL mod) //(a*b)%c a,b,c<2^63{    return (a*b-(LL)(a/(long double)mod*b+1e-3)*mod+mod)%mod;}LL pow_mod(LL a,LL b,LL mod) // a^b%mod{    LL ans=1;    a=a%mod;    while(b)    {        if(b&1)        {            ans=mult_mod(ans,a,mod);        }        a=mult_mod(a,a,mod);        b=b>>1;    }    return ans;}//以a为基,n-1=x*2^t      a^(n-1)=1(mod n)  验证n是不是合数//一定是合数返回true,不一定返回falsebool check(LL a,LL n,LL x,LL t){    LL ret=pow_mod(a,x,n);    LL last=ret;    for(int i=1;i<=t;i++)    {        ret=mult_mod(ret,ret,n);        if(ret==1 && last!=1 && last!=n-1) return true;//合数        last=ret;    }    if(ret!=1) return true;    else return false;}// Miller_Rabin()算法素数判定//是素数返回true.(可能是伪素数,但概率极小)//合数返回false;bool Miller_Rabin(long long n){    if(n<2)return false;    if(n==2) return true;    if( (n&1)==0) return false;//偶数    LL x=n-1;    LL t=0;    while( (x&1)==0 ) { x>>=1;t++;}    for(int i=0;i<S;i++)    {        LL a=rand()%(n-1)+1;//rand()需要stdlib.h头文件        if(check(a,n,x,t))        return false;//合数    }    return true;}int main(){    // n,m;    while(~scanf("%lld%lld",&n,&m))    {        LL sum=0;        for(int i=0;i<m;i++)            sum=sum*n+1;      //  printf("%lld",sum);        if(Miller_Rabin(sum))        printf("YES\n");        else        printf("NO\n");    }    return 0;}

米勒罗宾算法还是很快的 理论复杂度是log2(n)*测试数据

但是因为这个模板是对long long进行处理的,long long 之间相乘就可能会出现溢出问题,所以使用了快速乘,然而有一次在bc上就T了。。。

所以学了一种黑科技优化了快速乘 另外题面中如果是要判断int范围的数 就不使用快速乘的算法,会快很多。 

米勒罗宾的

假如p是质数,且Gcd(a,p)=1,那么 a(p-1) ≡1(mod p)。

即:假如a是整数,p是质数,且a,p互质(即两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1。

(百度百科)//gcd为最大公约数

所以的质数都满足 但可能有少数合数满足 所以就采用多次判定

其他代码问题 注释写的很清楚了





 





0 0
原创粉丝点击