普通的素数测试我们有O(√ n)的试除算法。事实上,我们有O(s*log³n)的算法。

下面就介绍一下Miller_Rabbin算法思想:

定理一:假如p是质数,且(a,p)=1,那么a^(p-1)≡1(mod p)。即假如p是质数,且a,p互质,那么a的(p-1)次方除以p的余数恒等于1。(费马小定理)

定理二:如果p是一个素数,那么对于x(0<x<p),若x^2 mod p 等于1,则x=1或p-1。

它利用了费马小定理,即:如果p是质数,且a,p互质,那么a^(p-1) mod p恒等于1。也就是对于所有小于p的正整数a来说都应该复合a^(p-1) mod p恒等于1。那么根据逆否命题,对于一个p,我们只要举出一个a(a<p)不符合这个恒等式(就是a^(p-1) mod p恒等于1式子),则可判定p不是素数。Miller-rabin算法就是多次用不同的a来尝试p是否为素数。

但是每次尝试过程中还做了一个优化操作,以提高用少量的a检测出p不是素数的概率。这个优化叫做二次探测。它是根据一个定理:如果p是一个素数,那么对于x(0<x<p),若x^2 mod p 等于1,则x=1或p-1。逆否命题:如果对于x(0<x<p),若x^2 mod p 不等于1,则p不是素数。根据这个定理,我们要计算a^(p-1) mod p是否等于1时,可以这样计算,设p-1=(2^t) * k。我们从a^k开始,不断将其平方直到得到a^(p-1),一旦发现某次平方后mod p等于1了,那么说明符合了二次探测定理的逆否命题使用条件,立即检查x是否等于1或p-1,如果不是则可直接判定p为合数。

一些问题:

1、对于p-1=(2^t) * k这个t的找法,可以记录一下x(x表示(p-1))的二进制形式下末尾有多少0,比如二进制(1000)B代表的是十进制(8)D,8的二进制数形式下末尾0有3个,那么也就是8=(2^3)*1;再例如二进制(11000)B代表的是十进制(24)D,24的二进制数形式下末尾0有3个,那么也就是24=(2^3)*3

2、对于随机数a的生成,因为我们这个算法判断的是p这个数是不是素数,那么素数和任意一个数都互质,题目又有要求a<p所以就随机生成一个[1,p-1]范围内的数就行

3、这个算法的复杂度是O(s*log³n),这个s是我们提前定好的,因为上面说了我们用的是费马小定理的逆否命题,但是该定理的逆命题是不一定成立的,但是令人可喜的是大多数情况是成立的。所以我们可以多找几个数a来验证一下p是否是素数,找几个数,这个多少数就是s

可以证明,使用以上两个定理以后,检验s次出错的概率至多为2^(-s),所以这个算法是很可靠的。

 1 #include<stdio.h>
2 #include<string.h>
3 #include<iostream>
4 #include<algorithm>
5 #include<queue>
6 #include<map>
7 #include<vector>
8 #include<math.h>
9 #define mem(a,x) memset(a,x,sizeof(a))
10 using namespace std;
11 typedef long long LL;
12 const int maxn=50005;
13 const int mod=26;
14 const int INF=0x3f3f3f3f;
15 const int Times = 10;
16 const int N = 5500;
17 LL ct, cnt;
18 LL fac[N], num[N];
19 LL gcd(LL a, LL b) //求两数最大公因子
20 {
21 return b? gcd(b, a % b) : a;
22 }
23 LL multi(LL a, LL b, LL m) //快速乘
24 {
25 LL ans = 0;
26 a %= m;
27 while(b)
28 {
29 if(b & 1)
30 {
31 ans = (ans + a) % m;
32 b--;
33 }
34 b >>= 1;
35 a = (a + a) % m;
36 }
37 return ans;
38 }
39 LL pow(LL a, LL b, LL m) //快速幂
40 {
41 LL ans = 1;
42 a %= m;
43 while(b)
44 {
45 if(b & 1)
46 {
47 ans = multi(ans, a, m);
48 b--;
49 }
50 b >>= 1;
51 a = multi(a, a, m);
52 }
53 return ans;
54 }
55 bool Miller_Rabin(LL n) //判断是不是素数
56 {
57 if(n == 2) return true;
58 if(n < 2 || !(n & 1)) return false;
59 LL m = n - 1;
60 int k = 0;
61 while((m & 1) == 0)
62 {
63 k++; //这个k就是我们讲的时候的t
64 m >>= 1; //这个m就是k
65 }
66 for(int i=0; i<Times; i++) //Times就是我们事先定义的s(要找a的个数)
67 {
68 LL a = rand() % (n - 1) + 1; //找一个[1,n-1]内的任意数
69 LL x = pow(a, m, n);
70 LL y = 0;
71 for(int j=0; j<k; j++)
72 {
73 y = multi(x, x, n);
74 if(y == 1 && x != 1 && x != n - 1) return false;
75 x = y;
76 }
77 if(y != 1) return false;
78 }
79 return true;
80 }
81 int main()
82 {
83 LL n;
84 while(cin>>n)
85 {
86 if(Miller_Rabin(n))
87 printf("是素数\n");
88 else printf("不是素数\n");
89 }
90 return 0;
91 }

Miller_Rabbin算法判断大素数的更多相关文章

  1. Miller_Rabbin算法判断大素数,Pollard_rho算法进行质因素分解

    Miller-rabin算法是一个用来快速判断一个正整数是否为素数的算法.它利用了费马小定理,即:如果p是质数,且a,p互质,那么a^(p-1) mod p恒等于1.也就是对于所有小于p的正整数a来说 ...

  2. GCDLCM 【米勒_拉宾素数检验 (判断大素数)】

    GCDLCM 题目链接(点击) 题目描述 In FZU ACM team, BroterJ and Silchen are good friends, and they often play some ...

  3. 重复造轮子之RSA算法(一) 大素数生成

    出于无聊, 打算从头实现一遍RSA算法 第一步, 大素数生成 Java的BigInteger里, 有个现成的方法 public static BigInteger probablePrime(int ...

  4. 与数论的爱恨情仇--01:判断大素数的Miller-Rabin

    在我们需要判断一个数是否是素数的时候,最容易想到的就是那个熟悉的O(√n)的算法.那个算法非常的简单易懂,但如果我们仔细想想,当n这个数字很大的时候,这个算法其实是不够用的,时间复杂度会相对比较高. ...

  5. 记一次使用快速幂与Miller-Rabin的大素数生成算法

    大家都知道RSA的加密的安全性就是能够找到一个合适的大素数,而现在判断大素数的办法有许多,比如Fermat素性测试或者Miller-Rabin素性测试,而这里我用了Miller-Rabin素性测试的算 ...

  6. POJ 1811 大素数判断

    数据范围很大,用米勒罗宾测试和Pollard_Rho法可以分解大数. 模板在代码中 O.O #include <iostream> #include <cstdio> #inc ...

  7. HDU 4910 Problem about GCD 找规律+大素数判断+分解因子

    Problem about GCD Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  8. 【算法编程】基于Miller-Rabin的大素数测试

    基本原理: 费尔马小定理:如果p是一个素数,且0<a<p,则a^(p-1)%p=1.        利用费尔马小定理,对于给定的整数n,可以设计素数判定算法,通过计算d=a^(n-1)%n ...

  9. (Miller Rabin算法)判断一个数是否为素数

    1.约定 x%y为x取模y,即x除以y所得的余数,当x<y时,x%y=x,所有取模的运算对象都为整数. x^y表示x的y次方.乘方运算的优先级高于乘除和取模,加减的优先级最低. 见到x^y/z这 ...

随机推荐

  1. Docker Java 镜像基础(四)

    基于官方提供的centos 7.2.1511 基础镜像构建JDK 和tomcat 镜像,先构建JDK镜像,然后在基于JDK镜像构建tomcat镜像 构建 centos:latest 基础镜像: # 下 ...

  2. 改进你的c#代码的5个技巧(四)

    像每一篇文章一样,我会重复几行.我在我的Core i3 CPU.4GB主内存和Windows 7平台上测试了以下代码.如果你在不同的硬件配置或使用不同的平台,那么你的输出可能会随着我的输出屏幕而变化, ...

  3. 【EXPDP】导出全部表的时候,选择不导出某个表

    导出的时候指定某一张表不导出的话,一般都用的是数据泵的expdp来操作 具体方法是: expdp test/test dumpfile=test.dmp directory=test_dir excl ...

  4. HTML&CSS:构建网站不能不说的那些事儿

    很高兴你能看到这个专栏!俗话说得好,相逢即是缘分,没准你和我在上一世也曾有过五百次的回眸,才得此一面.说的有点恶心了,咱还是书归正传,说说这个专栏吧. 这个专栏主要讲的是 HTML 和 CSS 的页面 ...

  5. SpringBoot @Value 解析集合配置

    引自:https://jitwxs.cn/d6d760c4.html 一.前言 在日常开发中,经常会遇到需要在配置文件中,存储 List 或是 Map 这种类型的数据.Spring 原生是支持这种数据 ...

  6. 使用npm install安装项目依赖的时候报错

    使用npm install安装项目依赖的时候报错: npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! node-sass@4.14.1 postin ...

  7. C++中输出变量类型的方法

    C++中输出变量类型的方法 在c++中输出变量或者数据类型,使用typeid().name()的方法.如下例子: #include <iostream> #include <stri ...

  8. JavaScript中函数的this指向!

    JavaScript的this的指向问题! 这是我自己敲的, 报错! <button>点击查看绑定事件的this指向!</button> <script> // 函 ...

  9. 在vSphere中为不同服务器配置IPMI功能

    在vSphere HA中如果要配置并启用DPM功能,需要记录服务器远程管理接口的IP地址(不是ESXi的IP地址,而是另一个独立的IP地址,是与ESXi服务器同一网段的另一个IP地址)与MAC地址.远 ...

  10. Linux sudo权限提升漏洞整改方法

    一.漏洞概述 1月26日,Sudo发布安全通告,修复了一个类Unix操作系统在命令参数中转义反斜杠时存在基于堆的缓冲区溢出漏洞.当sudo通过-s或-i命令行选项在shell模式下运行命令时,它将在命 ...