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 大素数测试的更多相关文章

  1. Miller_Rabbin大素数测试

    伪素数: 如果存在和n互素的正整数a满足a^(n-1)≡1(mod n),则n是基于a的伪素数. 是伪素数但不是素数的个数是非常非常少的,所以如果一个数是伪素数,那么他几乎是素数. Miller_Ra ...

  2. Miller-Rabin大素数测试模板

    根据费马小定理: 对于素数n,a(0<a<n),a^(n-1)=1(mod n) 如果对于一个<n的正整数a,a^(n-1)!=1(mod n),则n必不是素数. 然后就可以随机生成 ...

  3. 【算法编程】基于Miller-Rabin的大素数测试

    基本原理: 费尔马小定理:如果p是一个素数,且0<a<p,则a^(p-1)%p=1.        利用费尔马小定理,对于给定的整数n,可以设计素数判定算法,通过计算d=a^(n-1)%n ...

  4. Miller Robin大素数判定

    Miller Robin算法 当要判断的数过大,以至于根n的算法不可行时,可以采用这种方法来判定素数. 用于判断大于2的奇数(2和偶数需要手动判断),是概率意义上的判定,因此需要做多次来减少出错概率. ...

  5. miller——rabin判断素数

    我们首先看这样一个很简单的问题:判定正整数\(n\)是否为素数 最简单的做法就是枚举\(2\)到\(n\)的所有数,看是否有数是\(n\)的因数,时间复杂度\(O(n)\) 稍微优化一下发现只要枚举\ ...

  6. 大素数测试的Miller-Rabin算法

    Miller-Rabin算法本质上是一种概率算法,存在误判的可能性,但是出错的概率非常小.出错的概率到底是多少,存在严格的理论推导. 一.费马小定理 假如p是质数,且gcd(a,p)=1,那么 a(p ...

  7. 大素数测试 求因子 poj 1811

    抄别人的 #include<stdio.h> #include<string.h> #include<algorithm> #include<stdlib.h ...

  8. hdu 6169 Senior PanⅡ Miller_Rabin素数测试+容斥

    Senior PanⅡ Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 524288/524288 K (Java/Others) Pr ...

  9. 关于素数:求不超过n的素数,素数的判定(Miller Rabin 测试)

    关于素数的基本介绍请参考百度百科here和维基百科here的介绍 首先介绍几条关于素数的基本定理: 定理1:如果n不是素数,则n至少有一个( 1, sqrt(n) ]范围内的的因子 定理2:如果n不是 ...

随机推荐

  1. 洛谷—— P1725 琪露诺

    https://www.luogu.org/problem/show?pid=1725 题目描述 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精.某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来.但是这 ...

  2. Android GIS开发系列-- 入门季(5) FeatureLayer加载本地shp文件与要素查询

    FeatureLayer是要素图层,也是Arcgis的主要图层.用这个图层可以加载本地的shp文件.下面我们看怎样加载shp文件到MapView中.查看ArcGis API可知FeatureLayer ...

  3. bridge 上网

    手头有一台机器上有一个虚拟机 虚拟机为桥接 本机为静态IP上网 想让虚拟机上网的方式是 本机不设ip 网卡设置DHCP. 虚拟机设置静态ip

  4. RAC fail over 测试

    oracle rac 11gr2中提供了多种 failover方式,这里只测试 server side TAF. 也就是说在server端配置的failover.这种配置方式的好处就是,如果有什么改动 ...

  5. 表单中的日期 字符串和Javabean中的日期类型的属性自动转换

    搞了一上午的bug最终还是因为自己springMVC的注解不熟悉的原因,特记录. 在实际操作中经常会碰到表单中的日期 字符串和Javabean中的日期类型的属性自动转换, 而springMVC默认不支 ...

  6. 二维数组的查找,刷题成功——剑指Offer

    今天又做了一道题目,通过啦,欧耶! https://www.nowcoder.net/practice/abc3fe2ce8e146608e868a70efebf62e?tpId=13&tqI ...

  7. 解决MyEclipse中导入项目@Override错误

    做项目的时候,同事那边电脑上编译通过的java代码,或者是网上下载的例子代码,导入project后却是编译不通过,总是@override报错,把@override去掉就好了,有时候@Override出 ...

  8. 《iOS Human Interface Guidelines》——Wallet

    Wallet Wallet(钱包)帮助人们查看和管理Pass(凭证),这是一种相似于登机牌.优惠券.会员卡.奖励卡和各种票的物理凭证的数字替代.Wallet也同意人们加入信用卡.借记卡和储值卡来和Ap ...

  9. CentOS yum时出现“Could not retrieve mirrorlist ”的解决的方法——resolv.conf的配置

    原因:没有配置resolv.conf 解决方法: 到/etc文件夹下配置resolv.conf增加nameserver IP,如: nameserver 8.8.8.8 nameserver 8.8. ...

  10. DDM实践:数据库秒级平滑扩容方案

    本文部分内容节选自华为云帮助中心的分布式数据库中间件(DDM)服务的产品介绍 背景 随着业务增长,逻辑库存储空间不足,并发压力较大. 解决方案 此时可对DDM实例逻辑库进行平滑扩容,通过增加RDS实例 ...