普通的素数测试我们有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. SQL LEN()函数用法

    含义: LEN 函数返回文本字段中值的长度. 返回字符表达式中的字符数 SQL LEN() 语法 SELECT LEN(column_name) FROM table_name 举例: 1.LEN对相 ...

  2. 【MySQL】DDL数据定义语言的基本用法create、drop和alter(增删改)

    DDL 的基础语法 文章目录 DDL 的基础语法 对数据库进行定义 对数据表进行定义 创建表结构(数据表) 设计工具 修改表结构 小结 参考资料 简单复习一波 SQL必知必会 DDL 的英文全称是 D ...

  3. linux命名小技巧(持续更新)

    一   向某个文件批量加入内容 1.1 向/etc/wxm文件添加一大段内容可以使用这个命令 [root@registry easyrsa3]# cat <<EOF >varsset ...

  4. CTFshow-萌新赛杂项_劝退警告

    下载附件 https://www.lanzous.com/i9wocah 下载后得到一个劝退警告.zip 解压得到一张gif图片 使用binwalk分析发现包含zip 于是拿到了一个压缩包 打开后发现 ...

  5. CobalStrike 4.0 生成后门几种方式 及 主机上线后基础操作

    出品|MS08067实验室(www.ms08067.com) 本文作者:BlackCat(Ms08067内网安全小组成员) CobalStrike 4.0 生成后门几种方式 步骤:Attacks-〉P ...

  6. Unix Socket 代理服务 unix域套接字

    基于Unix Socket的可靠Node.js HTTP代理实现(支持WebSocket协议) - royalrover - 博客园 https://www.cnblogs.com/accordion ...

  7. JAXB学习(一):概述

    pre.XML { background-color: rgba(255, 204, 204, 1); padding-left: 25px } JAXB是 Java Architecture for ...

  8. 【Coredump】调试之旅

    测试反馈,core了. 拿到环境,发现6和11,一个是重复释放,一个是非法指针. 用GDB一挂 ,发现 1 GNU gdb (GDB) 7.5 2 Copyright (C) 2012 Free So ...

  9. Java SPI 与 Dubbo SPI

    SPI(Service Provider Interface)是JDK内置的一种服务提供发现机制.本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类.这样可以在运行时,动 ...

  10. 如何设计一个亿级网关(API Gateway)?

    1.背景 1.1 什么是API网关 API网关可以看做系统与外界联通的入口,我们可以在网关进行处理一些非业务逻辑的逻辑,比如权限验证,监控,缓存,请求路由等等. 1.2 为什么需要API网关 RPC协 ...