Miller Rabin 大素数测试
PS:本人第一次写随笔,写的不好请见谅。
接触MillerRabin算法大概是一年前,看到这个算法首先得为它的神奇之处大为赞叹,竟然可以通过几次随机数据的猜测就能判断出这数是否是素数,虽然说是有误差率,但是相对于他比其他素数判断的高效,真的是可以说是完美级。那时候忙于找工作,所以也没有细究,现在空下来终于对这个算法有了一定的理解。
先说两个定理:
(1) 当x<p时,满足x^(p-1) % p = 1,说明x与p互质;
(2) 当x<p时,满足x^2 % p = 1; x的解为 x = 1 或者 x = p -1;
根据第一个定理,我们可以在[2,p-1)中间随机选择一个数,然后根据定理1判断是否是素数(测试准确率跟测试次数有关,多次检测)。定理2可以做二次探索。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
using namespace std;
#define S 10 long mod_mul(long a,long b,long n) {
long res = ;
while(b) {
if(b&)
res = (res + a) % n;
a = (a + a) % n;
b >>= ;
}
return res;
} long mod_exp(long a, long b, long n) {
long res = ;
while(b) {
if(b&)
res = mod_mul(res, a, n);
a = mod_mul(a, a, n);
b >>= ;
}
return res;
} bool miller_rabin(long n) { //过滤器
if(n == || n == || n == || n == || n == ) return true;
if(n == || !(n%) || !(n%) || !(n%) || !(n%) || !(n%)) return false; long x, pre, u;
int i, j, k = ;
u = n - ; //要求x^u % n while(!(u&)) { //如果u为偶数则u右移,用k记录移位数
k++; u >>= ;
} srand(time());
for(i = ; i < S; ++i) { //进行S次测试
x = rand()%(n-) + ; //在[2, n)中取随机数
if((x%n) == ) continue; x = mod_exp(x, u, n); //先计算(x^u) % n,
pre = x;
for(j = ; j < k; ++j) { //把移位减掉的量补上,并在这地方加上二次探测
x = mod_mul(x, x, n);
if(x == && pre != && pre != n-) return false; //二次探测定理,这里如果x = 1则pre 必须等于 1,或则 n-1否则可以判断不是素数
pre = x;
}
if(x != ) return false; //费马小定理
}
return true;
} int main()
{
for(int i=;i<;++i)
if(miller_rabin(i))
cout<<i<<" ";
return ;
}
mod_mul与mod_exp是关于求模。不要看这两个函数很高大上,其实换种形式会更加理解。
long mod_mul(long a,long b,long n) { //求 (a*b)%n
//在不考虑数据上移时,先求a*b的值
long res = ; // res表示a*b的积
//举例 5(十进制) * 1101(2进制) = 5 * 2^0 + 5*0*2^1 + 5*2^2+5*2^3;
while(b) {
if(b&)
res = res + a;
a = *a;
b >>= ;
}
return res%n; //最后求模
} long mod_exp(long a, long b, long n) {
long res = ;
// res = a^b,把b分解成二进制
while(b) {
if(b&)
res = res * a;
a = a*a;
b >>= ;
}
return res%n;
}
现在讲米勒算法:
1、n为待判定数字,先取一个数u = n - 1;
2、通过循环除二,分解成 u(原) = u(新) * 2^k;
3、随机出x,x为[2,n),判断 x ^(u*2^k)%n == 1, 式子分解 [(x^u)%n ]^(2^k) %n == 1; 先计算 x= x ^ u % n;然后计算 x^(2^k) % n == 1;
4、如何计算x^(2^k) = (x^2)^(2^(k-1)); 并且可知,当x^2 % n == 1时,无需计算2^(k-1); 当x^2 % n == 1时, x ! = 1 或者 x != n-1则可判断该数为合数
5、循环测试,如果最后都没有return false,则可认为该数时质数。
例题有hdu2138:
注意点:虽然题目中数字都在32位整型之内,但是再做加法的时候,大小会超。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
using namespace std;
//a容易越界,res容易越界。因为有加号。
int mod_mul(__int64 a,int b,int n)
{
__int64 res = ;
while(b)
{
if(b&) res = (res+a)%n;
a = (*a)%n;
b >>= ;
}
return (int)res;
} int mod_exp(int a,int b,int n)
{
int res = ;
while(b)
{
if(b&) res = mod_mul(res,a,n);
a = mod_mul(a,a,n);
b >>= ;
}
return res;
} bool rabin_miller(int n)
{
if(n== || n== || n== || n== || n== || n==) return true;
if(n<= || n%== || n%== || n%== || n%== || n%== || n%==) return false;
int u,k,x,pre;
u = n-;
k = ;
while(u& ==)
{
++k;
u >>= ;
}
srand(time());
int s = ;
while(s--)
{
x = rand()%(n-)+;
pre = x = mod_exp(x,u,n);
for(int i=;i<k;++i)
{
x = mod_mul(x,x,n);
if(x == && pre != && pre != n-) return false;
pre = x;
}
if(x != ) return false;
}
return true;
} int main()
{
int n;
while(~scanf("%d",&n))
{
int ans = ;
for(int i=;i<n;++i)
{
int a;
scanf("%d",&a);
if(rabin_miller(a))
++ans;
}
printf("%d\n",ans);
} return ;
}
Miller Rabin 大素数测试的更多相关文章
- Miller_Rabbin大素数测试
伪素数: 如果存在和n互素的正整数a满足a^(n-1)≡1(mod n),则n是基于a的伪素数. 是伪素数但不是素数的个数是非常非常少的,所以如果一个数是伪素数,那么他几乎是素数. Miller_Ra ...
- Miller-Rabin大素数测试模板
根据费马小定理: 对于素数n,a(0<a<n),a^(n-1)=1(mod n) 如果对于一个<n的正整数a,a^(n-1)!=1(mod n),则n必不是素数. 然后就可以随机生成 ...
- 【算法编程】基于Miller-Rabin的大素数测试
基本原理: 费尔马小定理:如果p是一个素数,且0<a<p,则a^(p-1)%p=1. 利用费尔马小定理,对于给定的整数n,可以设计素数判定算法,通过计算d=a^(n-1)%n ...
- Miller Robin大素数判定
Miller Robin算法 当要判断的数过大,以至于根n的算法不可行时,可以采用这种方法来判定素数. 用于判断大于2的奇数(2和偶数需要手动判断),是概率意义上的判定,因此需要做多次来减少出错概率. ...
- miller——rabin判断素数
我们首先看这样一个很简单的问题:判定正整数\(n\)是否为素数 最简单的做法就是枚举\(2\)到\(n\)的所有数,看是否有数是\(n\)的因数,时间复杂度\(O(n)\) 稍微优化一下发现只要枚举\ ...
- 大素数测试的Miller-Rabin算法
Miller-Rabin算法本质上是一种概率算法,存在误判的可能性,但是出错的概率非常小.出错的概率到底是多少,存在严格的理论推导. 一.费马小定理 假如p是质数,且gcd(a,p)=1,那么 a(p ...
- 大素数测试 求因子 poj 1811
抄别人的 #include<stdio.h> #include<string.h> #include<algorithm> #include<stdlib.h ...
- hdu 6169 Senior PanⅡ Miller_Rabin素数测试+容斥
Senior PanⅡ Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 524288/524288 K (Java/Others) Pr ...
- 关于素数:求不超过n的素数,素数的判定(Miller Rabin 测试)
关于素数的基本介绍请参考百度百科here和维基百科here的介绍 首先介绍几条关于素数的基本定理: 定理1:如果n不是素数,则n至少有一个( 1, sqrt(n) ]范围内的的因子 定理2:如果n不是 ...
随机推荐
- [luoguP1196] 银河英雄传说(并查集)
传送门 记录 up[x] 表示 x 上方有多少个 all[x] 表示当前连通的有多少个 find 的时候 和 合并的时候 更新一下即可 ——代码 #include <cstdio> #in ...
- 20180906关于mysql启动
转自 https://blog.csdn.net/sqlserverdiscovery/article/details/52808541
- BAT经典面试题,深入理解Java内存模型JMM
Java 内存模型 Java 内存模型(JMM)是一种抽象的概念,并不真实存在,它描述了一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段.静态字段和构成数组对象的元素)的访问方式.试图屏 ...
- 11、Java并发性和多线程-Java内存模型
以下内容转自http://ifeve.com/java-memory-model-6/: Java内存模型规范了Java虚拟机与计算机内存是如何协同工作的.Java虚拟机是一个完整的计算机的一个模型, ...
- ssh连接断开后 shell进程退出
问题描述:当SSH远程连接到服务器上,然后运行一个服务 ./catalina.sh start,然后把终端开闭(切断SSH连接)之后,发现该服务中断,导致网页无法访问. 解决方法:使用nohup命 ...
- MVC路由中特殊URL匹配规则
*匹配*用来匹配URL剩余部分 贪婪匹配规则贪婪匹配会找到最后一个符合条件的“字面量”为止
- 使用系统存储过程来监控SQLServer进程和会话具体解释
承接上文,本文讲述怎样使用系统存储过程来监控系统. SQLServer相同也提供了一系列系统存储过程用于监控SQLServer,获取当前进程.会话.请求以及锁定的具体信息.本文将演示系统存储过程 ...
- 22、Cocos2dx 3.0游戏开发找小三之音乐与音效:假如世界上没有了音乐,你的耳朵会孤单吗?
重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/30485103 假如世界上没有了音乐,在森林里.我们听 ...
- 数据挖掘算法学习(八)Adaboost算法
本文不定期更新.原创文章,转载请附上链接http://blog.csdn.net/iemyxie/article/details/40423907 谢谢 Adaboost是一种迭代算法,其核心思想是针 ...
- java学习笔记:eclipse的workspace和working set
我将这二个东西搞混了. 看上去,workspace 类似于VS里的解决方案,而working set则像VS里的解决方案文件夹,是个逻辑概念. VS里的解决方案是个文件,而eclipse里的works ...