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. hdu 1874 dijkstra 队列实现 比数组高效特别在稀疏图

    参考  http://blog.csdn.net/zhuyingqingfen/article/details/6370561 刘汝佳白皮书 #include<stdio.h> #incl ...

  2. jQuery WeUI 组件下拉刷新和滚动加载的实现

    最近在做手机版使用到了下拉刷新和滚动加载,记录一下实现过程: 一.引入文件 ? 1 2 3 4 <link rel="stylesheet" href="Conte ...

  3. Power of Matrix 等比数列求和 矩阵版!

    #include<iostream> #include<cstdio> #include<cmath> #include<cstring> #inclu ...

  4. mysql bin-log 设置

    mysql 的事物日至为 [root@localhost mysql]# ls -ldtr mysql-bin.* -rw-rw---- mysql mysql 4月 : mysql-bin. -rw ...

  5. 如何在eclipse中用maven编译

    在eclipse中用maven编译的方法: 在项目中的“pom.xml”文件上点击右键,在弹出的菜单中选择“Run AS”à“Maveninstall”来编译和生成项目.如下图所示: 在编译和生成过程 ...

  6. IOS--JSON数据解析成字典

    JSON解析成字典 {} –>字典 [] –>数组 ""–>字符串 11/11.1–>NSNumber true/false –>NSNumber n ...

  7. 用Arduino对Apple手表进行远程红外控制

    描写叙述 用于控制随意红外设备的Apple手表及iPhone应用. IOS应用发送HTTP请求至一个或多个带有以太网插板的Arduino.Arduino正在解析http请求并发送红外信号.Arduin ...

  8. ftk学习记(输入框篇)

    [ 声明:版权全部.欢迎转载.请勿用于商业用途. 联系信箱:feixiaoxing @163.com] 昨天讲了进度条,我们还是看看它的运行效果是怎么样的.截图例如以下, 进度条使用的情况还是比較多的 ...

  9. 【翻译自mos文章】注意: ASMB process exiting due to lack of ASM file activity

    注意: ASMB process exiting due to lack of ASM file activity 參考原文: NOTE: ASMB process exiting due to la ...

  10. A new Graph Game

    点击打开链接 题意:给你一张N个节点的无向图.然后给出M条边,给出第 I 条边到第J条边的距离.然后问你是否存在子环,假设存在,则输出最成环的最短距离和 解析:构图:选定源点及汇点,然后将源点至个点流 ...