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

  1. 【HOJ1356】【Miller_rabin素性测试】Prime Judge

    Given a positive integer, your job is writing a program to determine whether it is a prime number or ...

  2. 优化后的二次测试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 ...

  3. Miller_Rabin (米勒-拉宾) 素性测试

    之前一直对于这个神奇的素性判定方法感到痴迷而又没有时间去了解.借着学习<信息安全数学基础>将素性这一判定方法学习一遍. 首先证明一下费马小定理. 若p为素数,且gcd(a, p)=1, 则 ...

  4. 【算法杂谈】Miller-Rabin素性测试算法

    额,我们今天来讲一讲Miller-Rabin素性测试算法. 读者:怎么又是随机算法!!!(⊙o⊙)… [好了,言归正传] [费马小定理] 费马小定理只是个必要条件,符合费马小定理而非素数的数叫做Car ...

  5. POJ 1811 Prime Test 素性测试 分解素因子

    题意: 给你一个数n(n <= 2^54),判断n是不是素数,如果是输出Prime,否则输出n最小的素因子 解题思路: 自然数素性测试可以看看Matrix67的  素数与素性测试 素因子分解利用 ...

  6. Miller-Rabin素性测试|Pollard's Rho算法

    Miller-Rabin 素性测试 Miller-Rabin 素数测试 一本通上的M-R不透彻啊~ Miller-Rabin是利用随机化算法判断一个数是合数还是素数. 首先,如果一个数N是素数,那么他 ...

  7. miller_rabin_素性测试

    摘自:http://blog.csdn.net/pi9nc/article/details/27209455 看了好久没看懂,最后在这篇博客中看明白了. 费马定理的应用,加上二次探测定理. Ferma ...

  8. Miller-Rabin素性测试

    有时候我们想快速的知道一个数是不是素数,而这个数又特别的大导致 $O(\sqrt n)$ 的算法也难以通过,这时候我们可以对其进行 Miller-Rabin 素数测试,可以很大概率测出其是否为素数. ...

  9. @总结 - 10@ Miller-Rabin素性测试与Pollard-Rho因数分解

    目录 @1 - 素性测试:Miller-Rabin算法@ @1.1 - 算法来源@ @1.2 - 算法描述@ @1.3 - 算法实现@ @2 - 因数分解:Pollard-Rho算法@ @2.0 - ...

随机推荐

  1. Java 文件

    章节 Java 基础 Java 简介 Java 环境搭建 Java 基本语法 Java 注释 Java 变量 Java 数据类型 Java 字符串 Java 类型转换 Java 运算符 Java 字符 ...

  2. poj 1027 Ignatius and the Princess II全排列

    Ignatius and the Princess II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ( ...

  3. python中pip的安装问题

    当系统中同时存在python2.python3的时候,在进行pip下载的时总出现不知道用哪个 情况,此时就需要这样做: python2 -m pip install numpy //使用pip给pyt ...

  4. 【pwnable.kr】lotto

    pwnable.好像最近的几道题都不需要看汇编. ssh lotto@pwnable.kr -p2222 (pw:guest) 直接down下来源码 #include <stdio.h> ...

  5. cf 782# A.Andryusha and Socks B.The Meeting Place Cannot Be Changed C.Andryusha and Colored Balloons

    看来快掉到灰名的蒟蒻涨rating也快... A题模拟一下就好(一开始还sb,, #include<bits/stdc++.h> #define LL long long using na ...

  6. SQL Server 语法大全

    SQL语句参考,包含Access.MySQL 以及 SQL Server 基础 创建数据库 CREATE DATABASE database-name 删除数据库 drop database dbna ...

  7. HDU_4960 2014多校9 Another OCD Patient DP

    其实现在想起来是个巨简单的DP,模型就跟LCS很像,比赛的时候居然没想出来,在聪哥提醒下还卡了个地方 就是说给定一串n个数字的序列,可以连续合并,最终使得序列是回文的,题目也给定了合并数字所需的代价, ...

  8. SPOJ RENT 01背包的活用+二分

    这个题目给定N航班的发出时间和结束时间以及价值,要求不冲突时间的最大价值 第一时间想到经典的N方DP,即对航班按发出时间排一下序之后每个i对前面的都扫一遍 时间过不了N有10万,只能想优化了,一开始想 ...

  9. jsp页面使用<% 语句%> SQL Server数据库报空指针异常(在控制台可以正常执行)

    一直反感用SQL Server数据库,很影响电脑性能!!数据库作业不得不用 前几天作业一直报空指针异常: 自己检查了所传参数,和数组不为空 数据库查询语句不为空 然后查看SQL服务是否启动  主要是S ...

  10. jQuery中:first,:first-child,first()的使用区别

    ul li:first  先获取页面中所有li节点对象数组,然后返回数组中的第一个li节点对象 . :first-child  选择器选取属于其父元素的第一个子元素的所有元素. first() 返回被 ...