Miller_Rabin素性测试
1. 为什么需要素性测试?
我们其实已经知道有一些判断素数的方法,比如:
遍历测试:待测试数n与2,3,...√n做除法判断余数是否为零,如果没有任何一个数可以整除n,则说明n为素数
Wilson定理:对于给定的正整数n,n是素数的充要条件为,则可以通过判断这个方程是否成立来判断n是否为素数
上面的方法都可以确定的判断出一个数是否为素数,但问题在于对于大整数,这两个算法都需要很大计算量和时间,能不能有一个更快速的判定算法呢?
答案是当前还没有一个更高效且能准确判定素数的方法。但借助随机算法和数论知识,已有可以非常高效且判定错误率很低的素数测试算法,即Millan_Rabin素性测试
2. 需要知道的知识
2.1 Fermat定理
费马定理的前提是a和n互质。当n本身就是素数的时候如果a<n那么a和n始终互素,费马定理是成立的,但n当不是素数,且a和n不互素的话不能用费马定理(也就是说费马定理不一定成立)
需要知道的是满足费马定理是素数的必要条件,但不是充分条件,也就是说是素数一定满足费马定理(如果一个数不满足费马定理就不是素数),但是满足费马定理的数字不一定是素数(称为伪素数,伪素数的数量较少,所以可以通过费马定理以比较大的概率判定一个数是否为素数)
令a=2,不满足2^(n-1) mod n = 1的n一定不是素数;如果满足的话则多半是素数。这样,一个比试除法效率更高的素性判断方法出现了:制作一张伪素数表,记录某个范围内的所有伪素数,那么所有满足2^(n-1) mod n = 1且不在伪素数表中的n就是素数。之所以这种方法更快,是因为我们可以使用二分法快速计算2^(n-1) mod n 的值,这在计算机的帮助下变得非常容易;在计算机中也可以用二分查找有序数列、Hash表开散列、构建Trie树等方法使得查找伪素数表效率更高。
那么伪素数的个数到底有多少?换句话说,如果我只计算2^(n-1) mod n的值,事先不准备伪素数表,那么素性判断出错的概率有多少?统计表明,在前10亿个自然数中共有50847534个素数,而满足2^(n-1) mod n = 1的合数n有5597个。这样算下来,算法出错的可能性约为0.00011。这个概率还是太高了,如果想免去建立伪素数表的工作,我们需要还需要改进素性判断的算法。
最简单的想法就是,我们刚才只考虑了a=2的情况。对于式子a^(n-1) mod n,取不同的a可能导致不同的结果。一个合数可能在a=2时通过了测试,但a=3时的计算结果却排除了素数的可能。于是,人们扩展了伪素数的定义,称满足a^(n-1) mod n = 1的合数n叫做以a为底的伪素数(pseudoprime to base a)。前10亿个自然数中同时以2和3为底的伪素数只有1272个,这个数目不到刚才的1/4。这告诉我们如果同时验证a=2和a=3两种情况,算法出错的概率降到了0.000025。容易想到,选择用来测试的a越多,算法越准确。通常我们的做法是,随机选择若干个小于待测数的正整数作为底数a进行若干次测试,只要有一次没有通过测试就立即把这个数扔回合数的世界。这就是Fermat素性测试。
人们自然会想,如果考虑了所有小于n的底数a,出错的概率是否就可以降到0呢?没想到的是,居然就有这样的合数,它可以通过所有a的测试(在满足费马定理前提的条件下)。Carmichael第一个发现这样极端的伪素数,他把它们称作Carmichael数。你一定会以为这样的数一定很大。错。第一个Carmichael数小得惊人,仅仅是一个三位数,561。前10亿个自然数中Carmichael数也有600个之多。Carmichael数的存在说明,我们还需要继续加强素性判断的算法。
2.2 二次探测定理
这个定理应该怎么理解呢?其实就是说,(x+1)(x-1)可以整除p,又因为p是素数,不可分割,所以要么是(x-1)这一部分整除了p(因为0<x<p,故x-1<p,所以x-1只能为0才能满足,所以此时x = 1),要么就是(x+1)整除了p(因为0<x<p,则1<x+1<p+1,故只有当x+1=p才能满足,此时x = p-1),所以满足条件的x=1或x=p-1
二次探测定理可以用来对费马定理做一个增强,以更高的概率确定一个数是否为素数,将两者融合,就可以得到Miller_Rabin算法。
3. Miller_Rabin定理
为什么说测试次数为k次,错误概率可降低之(1/4)^k呢?(这还是保守估计)
我的理解是,因为上面我们知道,同时通过2和3的费马测试的伪素数个数不到通过2的费马测试的个数的1/4,这还只是通过了费马测试,这里我们还进行了二次检测,所以错误率应该更低,且数字越大,能够同时通过更多数字费马测试的数越少(推测),所以错误率至少是(1/4)^k,实际中应该比这个还要低很多。
下面举个例子来说明Miller_Rabin算法判断素数的流程,我们来测试341是否为素数。首先可以验证341可以通过以2为底的Fermat测试,因为2^340 mod 341=1。如果341真是素数的话,那么2^170 mod 341只可能是1或340;当算得2^170 mod 341确实等于1时,我们可以继续查看2^85除以341的结果。我们发现,2^85 mod 341=32,这一结果并不满足x = 1或x = 340这一条件,所以和二次探测定理矛盾,这一结果摘掉了341头上的素数皇冠。
Miller-Rabin素性测试同样是不确定算法,我们把可以通过以a为底的Miller-Rabin测试的合数称作以a为底的强伪素数(strong pseudoprime)。第一个以2为底的强伪素数为2047。第一个以2和3为底的强伪素数则大到1 373 653。所以说Miller_Rabin算法可以看作Fermat测试的一个加强版,可以以更大的概率确定一个数是否为素数。再借助快速幂算法,同时可以加速这个进程,判定速度更快。
4. Miller_Rabin算法C++实现
#include <iostream>
#include <stdlib.h>
typedef long long int ll;
using namespace std; ll quick_mul (ll a, ll b, ll mod) {
ll res = ;
while(b) {
if(b & ) {
res = (res + a) % mod;
}
a = (a + a) % mod;
b >>= ;
}
return res;
} ll quick_pow(ll a, ll n, ll mod) {
ll res = ;
while(n) {
if(n & ) {
res = quick_mul(res, a, mod);
}
a = quick_mul(a, a, mod);
n >>= ;
}
return res;
} bool Miller_Rabin(ll n) {
if(n == ) {
return true;
}
if(n < || !(n & )) {
return false;
}
ll m = n-, k = ;
while(!(m&)) {
k++;
m >>= ;
}
// printf("m = %lld, k = %lld\n", m, k);
int iter = ;
for(int i = ; i < iter; i++) {
ll a = rand() % (n-) + ;
// printf("a = %lld\n", a);
ll x = quick_pow(a, m, n);
// printf("x = %lld\n", x);
ll y;
for(int j = ; j < k; j++) {
y = quick_pow(x, x, n);
// printf("y = %lld\n", y);
if(y == && x != && x != n-) {
return false;
}
x = y;
}
if(y != ) {
return false;
}
}
return true;
} int main(void) {
ll num;
printf("Please input the num you want to test:\n");
scanf("%lld", &num);
printf("%s\n", Miller_Rabin(num) ? "yes" : "no");
}
参考
https://blog.csdn.net/ECNU_LZJ/article/details/72675595
http://www.matrix67.com/blog/archives/234
本文很大程度参考了这两篇博文,都写的很好,值得学习:)
Miller_Rabin素性测试的更多相关文章
- 【HOJ1356】【Miller_rabin素性测试】Prime Judge
Given a positive integer, your job is writing a program to determine whether it is a prime number or ...
- 优化后的二次测试Miller_Rabin素性测试算法
ll random(ll n) { return (ll)((double)rand()/RAND_MAX*n + 0.5); } ll pow_mod(ll a,ll p,ll n) { ) ; l ...
- Miller_Rabin (米勒-拉宾) 素性测试
之前一直对于这个神奇的素性判定方法感到痴迷而又没有时间去了解.借着学习<信息安全数学基础>将素性这一判定方法学习一遍. 首先证明一下费马小定理. 若p为素数,且gcd(a, p)=1, 则 ...
- 【算法杂谈】Miller-Rabin素性测试算法
额,我们今天来讲一讲Miller-Rabin素性测试算法. 读者:怎么又是随机算法!!!(⊙o⊙)… [好了,言归正传] [费马小定理] 费马小定理只是个必要条件,符合费马小定理而非素数的数叫做Car ...
- POJ 1811 Prime Test 素性测试 分解素因子
题意: 给你一个数n(n <= 2^54),判断n是不是素数,如果是输出Prime,否则输出n最小的素因子 解题思路: 自然数素性测试可以看看Matrix67的 素数与素性测试 素因子分解利用 ...
- Miller-Rabin素性测试|Pollard's Rho算法
Miller-Rabin 素性测试 Miller-Rabin 素数测试 一本通上的M-R不透彻啊~ Miller-Rabin是利用随机化算法判断一个数是合数还是素数. 首先,如果一个数N是素数,那么他 ...
- miller_rabin_素性测试
摘自:http://blog.csdn.net/pi9nc/article/details/27209455 看了好久没看懂,最后在这篇博客中看明白了. 费马定理的应用,加上二次探测定理. Ferma ...
- Miller-Rabin素性测试
有时候我们想快速的知道一个数是不是素数,而这个数又特别的大导致 $O(\sqrt n)$ 的算法也难以通过,这时候我们可以对其进行 Miller-Rabin 素数测试,可以很大概率测出其是否为素数. ...
- @总结 - 10@ Miller-Rabin素性测试与Pollard-Rho因数分解
目录 @1 - 素性测试:Miller-Rabin算法@ @1.1 - 算法来源@ @1.2 - 算法描述@ @1.3 - 算法实现@ @2 - 因数分解:Pollard-Rho算法@ @2.0 - ...
随机推荐
- NO7 利用三剑客awk-grep-sed-head-tail等7种方法实践
·seq sequence #序列·sed stream editor #(三剑客老二)流编辑器.实现对文件的增删改替换查. -n #取消默认输出.sed -n '20,30 ...
- HDU - 3729 I'm Telling the Truth(二分匹配)
题意:有n个人,每个人给出自己的名次区间,问最多有多少个人没撒谎,如果有多解,输出字典序最大的解. 分析: 1.因为字典序最大,所以从后往前分析. 2.假设后面的人没说谎,并将此作为已知条件,然后从后 ...
- 10nm Ice Lake处理器值得等待!
处理器.显卡等产品往往习惯先在 Linux 平台测试,所以 Linux 的内核源码往往成为曝光新品的宝藏之地. 经查,在 Linux v5.2 内核最新源码的 x86 分支中,出现了多款 Ice La ...
- HihoCoder第七周:完全背包问题
1043 : 完全背包 时间限制:20000ms 单点时限:1000ms 内存限制:256MB 描述 且说之前的故事里,小Hi和小Ho费劲心思终于拿到了茫茫多的奖券!而现在,终于到了小Ho领取奖励的时 ...
- module已经装了但仍提示找不到的解决方法
今天遇到的问题:(这里只是个例子) 解决方法: npm clean cache --force 删了node_modules 和 package-lock ,然后npm install 如果再不行,看 ...
- 吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-facetime-video
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...
- css渐变实现
body{ width: 100%; height: 100%; overflow: hidden; } *{ margin: 0px; padding: 0px; font-size: 0px; } ...
- c\c++ 中字符串分割,并且转换为整形数据
在项目开发中,经常使用到字符串分割, 并且将其转换为整形(比如IP的分割获取,MAC地址的分割获取等),代码如下: #ifndef _UNICODE void StrToIntData( char * ...
- 超低功耗Sub-1GHz性价比首选方案:CMT2300
关于超低功耗Sub-1GHz射频收发器,目前性价比方面CMT2300是一款大多客户的首选方案,不管是成本方面还是性能方面,都能大大的满足客户的需求.下面为大家讲解下CMT2300 这款Sub-1GHz ...
- python--多线程的应用
python 多线程执行函数,以及调用函数时传参 import threading def func1(): print('this is function1') def func2(x,y): pr ...