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不是 ...
随机推荐
- 强连通图 HDU - 1269
为了训练小希的方向感,Gardon建立了一座大城堡,里面有N个房间(N<=10000)和M条通道(M<=100000),每个通道都是单向的,就是说若称某通道连通了A房间和B房间,只说明可以 ...
- Ubuntu 16.04安装VMware-Workstation-12
1.下载: https://download3.vmware.com/software/wkst/file/VMware-Workstation-Full-12.1.1-3770994.x86_64. ...
- Oracle Multitenant Environment (一) About
About oracle mulittenant environment The multitenant architecture enables an Oracle database to func ...
- 【Android】自己定义圆形ImageView(圆形头像 可指定大小)
近期在仿手Q的UI,这里面常常要用到的就是圆形头像,看到 在android中画圆形图片的几种办法 这篇文章,了解了制作这样的头像的原理.只是里面提供的方法另一个不足的地方就是不能依据实际需求改变图片的 ...
- 服务器Hot Spare热备
Hot Spare:热备用 当一个正在使用的磁盘发生故障后,一个空闲.加电并待机的磁盘将马上代替此故障盘,此方法就是热备用.热备用磁盘上不存储任何的用户数据,最多可以有8个磁盘作为热备用磁盘.一个热备 ...
- 畅谈HTML开发
现在,打开浏览器,各种各样的页面可以让人眼花缭乱,对于行外人看到的是美观效果是用户体验,对行内人很多其它的是关注技术和创造力. 对于开发者都知道DIV是一对html经常使用标签,DIV+CSS是一对非 ...
- 打造atom成为golang开发神器
在我在Windows系统上开发的日子里.我使用IDE开发数年之久.比如Visual Basic IDE, Borland Delphi IDE, Visual C++ 和最后的Visual Studi ...
- linux /proc/stat 文件说明
/proc/stat 文件内容 # cat /proc/stat cpu 1411 1322 3070 1193539 2790 0 268 0 0 0 cpu0 472 658 787 297933 ...
- oc73--NSArray使用
// // main.m // NSArray和NSString之间转换 #import <Foundation/Foundation.h> int main(int argc, cons ...
- ubuntu系统jdk安装及环境变量配置
一.安装jdk 1.下载linux版本jdk,我用的是最新版本1.8.0_102 2.打开终端,进入jdk的存放路径 3.解压.tar.gz文件 sudo tar zxvf jdk-8u102-lin ...