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

两个理论基础

(1)费马小定理:当 $p$ 为质数,有 $a^{p-1}\equiv 1(mod \ p)$,反过来不一定成立,也就是说,如果 $a, \ p$ 互质,且 $a^{p-1}\equiv 1(mod \ p)$,不能推出 $p$ 是质数,比如 $Carmichael$ 数

(2)二次探测:如果 $p$ 是素数,$0 < x < p$,则方程 $x^2 \equiv 1(mod \ p)$ 的解为 $x=1$ 或 $x=p-1$.

证一下二次探测定理:

易知 $ x^2-1 \equiv 0(mod \ p)$

$\because(x+1)(x-1) \equiv  0\ (mod \ p)$

$\because$ $p$ 为素数,只能分解为

$\because x+1 \equiv 0\ (mod \ p)$ 或 $x-1 \equiv 0\ (mod \ p)$

根据 $x$ 的取值范围,$x=1$ 或 $x=p-1$.

Fermat 素性测试

只根据费马小定理,易得一种检测质数的思路:

它的基本思想就是多次从 $\left [ 2, n-1 \right ]$ 中选取基 $a$,并检验是否每次都有 $a^{n-1} \equiv 1\ (mod \ n)$

bool millerRabin(int n) {
if (n < ) return n == ;
// test_time 为测试次数,建议设为不小于 8
// 的整数以保证正确率,但也不宜过大,否则会影响效率
int test_time = ;
for (int i = ; i <= test_time; ++i) {
int a = rand() % (n - ) + ;
if (qpow(a, n - , n) != )
{
printf("a:%d\n", a);
return false;
}
}
return true;
}

遗憾的是,由于费马小定理的逆定理并不成立 ,即满足  $a^{n-1} \equiv 1\ (mod \ n)$,$n$ 也不一定是素数。

卡迈克尔数

上面的做法中随机地选择 $a$,很大程度上降低了犯错概率,但是仍有一类数,上面的做法并不能准确地判断。

对于合数,如果对于所有与 $n$ 互素的正整数 $a$,都有同余式 $a^{n-1} \equiv 1\ (mod \ n)$ 成立,则合数 $n$ 为卡迈克尔数(Carmichael Number),又称费马伪素数。

而且我们知道,若 $n$ 为卡迈克尔数,则 $2^n-1$ 也是卡迈克尔数,从而卡迈克尔数的个数是无穷的。

在1~100000000范围内的整数中,只有255个Carmichael数。前3个Carmichael数是561,1105,1729。

Miller-Rabin测试

根据卡迈克尔数的性质,可知其一定不是 $p^e$.

不妨将费马小定理和二次探测定理结合起来使用:

  1. 对偶数和0、1、2直接判断
  2. 设要测试的数为 $n$,设$m$、$k$,满足 $n-1 = m2^k$(使其中 $m$ 为奇数)
  3. 我们先算出 $a^t$,然后不断地平方且进行二次探测(进行 $k$ 次)
  4. 最后根据费马小定理探测一次
  5. 多次取不同的 $a$ 进行上面3步

可以证明Miller-Rabbin算法单次出错的概率小于等于 $\frac{1}{4}$,若重复 $k$ 次,则出错概率降低至 ${(\frac{1}{4})}^k$。这是一个很保守的估计,实际效果要好得多。

#include<bits/stdc++.h>
using namespace std; typedef long long int ll; ll mod_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 mod_pow(ll a, ll n, ll mod)
{
ll res = ;
while (n)
{
if (n & )
res = mod_mul(res, a, mod);
a = mod_mul(a, a, mod);
n >>= ;
}
return res;
} // Miller-Rabin随机算法检测n是否为素数
bool Miller_Rabin(ll n)
{
if (n == )
return true;
if (n < || !(n & ))
return false;
ll m = n - , k = ;
while (!(m & ))
{
k++;
m >>= ;
}
for (int i = ; i <= ; i++) // 20为Miller-Rabin测试的迭代次数
{
ll a = rand() % (n - ) + ;
ll x = mod_pow(a, m, n);
ll y;
for (int j = ; j <= k; j++)
{
y = mod_mul(x, x, n);
if (y == && x != && x != n - )
return false;
x = y;
}
if (y != )
return false;
}
return true;
} int main()
{
ll n;
while(scanf("%lld", &n) == )
{
printf("%d\n", Miller_Rabin(n));
}
}

注:

(1)时间复杂度 $O(Slog^3)$($S$ 为测试次数)

(2)long long相乘可能会爆long long,所以使用快速乘

(3)当 $a$ 取遍30内的素数,$int$ 都不会出错

(4)记住几个素数19260817、23456789、2092876369、11111111111111111111111(23个1)

(5)还可以去 hihocodeCoder 1287 测一下板子

参考链接:

1. 百度百科——卡迈克尔数

2.OI WIKI——素数

3. https://blog.csdn.net/forever_dreams/article/details/82314237?tdsourcetag=s_pctim_aiomsg

4. https://blog.csdn.net/ECNU_LZJ/article/details/72675595

5. http://www.matrix67.com/blog/archives/234

Miller-Rabin素性测试的更多相关文章

  1. POJ1811_Prime Test【Miller Rabin素数测试】【Pollar Rho整数分解】

    Prime Test Time Limit: 6000MS Memory Limit: 65536K Total Submissions: 29193 Accepted: 7392 Case Time ...

  2. HDU1164_Eddy&#39;s research I【Miller Rabin素数测试】【Pollar Rho整数分解】

    Eddy's research I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

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

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

  4. 米勒罗宾素性测试(Miller–Rabin primality test)

    如何判断一个素是素数 效率很高的筛法 打个表 (素数的倍数一定是合数) 就可以解决问题. 筛选法的效率很高,但是遇到大素数就无能为力了. 米勒罗宾素性测试是一个相当著名的判断是否是素数的算法 核心为费 ...

  5. 与数论的厮守01:素数的测试——Miller Rabin

    看一个数是否为质数,我们通常会用那个O(√N)的算法来做,那个算法叫试除法.然而当这个数非常大的时候,这个高增长率的时间复杂度就不够这个数跑了. 为了解决这个问题,我们先来看看费马小定理:若n为素数, ...

  6. 素数与素性测试(Miller-Rabin测试)

    转载自Matrix大牛的博客 把代码翻译成C++ http://www.matrix67.com/blog/archives/234 题目链接: http://hihocoder.com/proble ...

  7. 【数学】【筛素数】Miller-Rabin素性测试 学习笔记

        Miller-Rabin是一种高效的随机算法,用来检测一个数$p$是否是素数,最坏时间复杂度为$\log^3 p$,正确率约为$1-4^{-k}$,$k$是检验次数. 一.来源     Mil ...

  8. Miller-Rabin 素性测试 与 Pollard Rho 大整数分解

    \(\\\) Miller-Rabin 素性测试 考虑如何检验一个数字是否为素数. 经典的试除法复杂度 \(O(\sqrt N)\) 适用于询问 \(N\le 10^{16}\) 的时候. 如果我们要 ...

  9. miller_rabin_素性测试

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

  10. POJ1811- Prime Test(Miller–Rabin+Pollard's rho)

    题目大意 给你一个非常大的整数,判断它是不是素数,如果不是则输出它的最小的因子 题解 看了一整天<初等数论及其应用>相关部分,终于把Miller–Rabin和Pollard's rho这两 ...

随机推荐

  1. JSON文件转为Excel

    前言 今天在帮老师做年终党统的时候,发现管理平台上没有将正在发展的同志的信息导出功能,只能一个一个点击进去查看,操作起来步骤很多很麻烦,所以我就想到了"扒"一下这个网页,扒下来发现 ...

  2. js实现放烟花效果——点击处会从下向上升起烟花

    一个box中,点击其中的任意位置,会有烟花从正下方升起到点击处,并燃放出一圈圆形的烟花.代码如下: 首先是布局以及样式: <style> .box{ width: 1100px; heig ...

  3. 人机交互技术 Week 2_History of HCI

    Recap: Interaction Design Interaction Design Designing interactive products to support people in the ...

  4. 用Python获取计算机网卡信息

    目录 0. 前言 1. 测试环境及关键代码解释 1.1 测试环境 1.1.1 系统: 1.1.2 开发工具: 2. 模块介绍及演示 2.1 platform模块使用示例 2.2 netifaces模块 ...

  5. docker&git&gitlab-安装/部署/新建

    --安装gcc yum -y install gcc --安装g++ yum -y install gcc-c++ --安装编译所需的包 yum -y install curl-devel expat ...

  6. 消息队列ActiveMQ

    什么是ActiveMQ ActiveMQ 是Apache出品,最流行的,能力强劲的开源消息总线.ActiveMQ 是一个完全支持JMS1.1和J2EE 1.4规范的 JMS Provider实现,尽管 ...

  7. asp.net core-2.在vs2017中创建asp.net core应用程序

    今天我们用vs2017创建一个asp.net core 的应用程序,打开vs2017 点击:文件—>项目,选择asp.net core web 应用程序 点击确定 红框内就昨天用控制台去创建的应 ...

  8. (三)XML基础(3):Xpath

    五.XPath:快速定位到节点 5.1 简介 5.2 语法 5.3 案例 XPath对有命名空间的xml文件和没有命名空间的xml定位节点的方法是不一样的,所以再对不同的xml需要进行不同的处理. 使 ...

  9. iframe滚动条充当浏览器滚动条

    在做博客项目的时候,使用了iframe,方便根据选择的文章类别切换显示的内容,但是文章一般都有很多,通过bootstrap的媒体列表的方式显示的话,iframe是一定会出现滚动条的,特别是我添加了一个 ...

  10. nlopt 二次优化

    /* * main.c * * Created on: Oct 9, 2018 * Author: lgh */ #include <stdio.h> #include <math. ...