素数判定
来源:互联网 发布: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为最大公约数
所以的质数都满足 但可能有少数合数满足 所以就采用多次判定
其他代码问题 注释写的很清楚了
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定
- 素数判定!
- 素数判定
- 素数判定
- 素数判定
- 使用PHP实现二分查找算法代码分享
- 虚函数中“虚”的理解
- 6.4.1 final成员变量
- 【Android 细节(二)】业务操作类的生命周期中的开始方法
- 近况.
- 素数判定
- Brown film faced plywood the worthy formply
- 回文字符串
- Android---4---布局之RelativeLayout
- 关于Android的ADB(Android Debug Bridge)的几种错误说明
- 浅谈sleep方法和wait方法的异同
- RPC-JSON
- thinkphp开发基本知识
- 习题2-19