Miller_Rabbin算法判断大素数
普通的素数测试我们有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算法判断大素数的更多相关文章
- Miller_Rabbin算法判断大素数,Pollard_rho算法进行质因素分解
Miller-rabin算法是一个用来快速判断一个正整数是否为素数的算法.它利用了费马小定理,即:如果p是质数,且a,p互质,那么a^(p-1) mod p恒等于1.也就是对于所有小于p的正整数a来说 ...
- GCDLCM 【米勒_拉宾素数检验 (判断大素数)】
GCDLCM 题目链接(点击) 题目描述 In FZU ACM team, BroterJ and Silchen are good friends, and they often play some ...
- 重复造轮子之RSA算法(一) 大素数生成
出于无聊, 打算从头实现一遍RSA算法 第一步, 大素数生成 Java的BigInteger里, 有个现成的方法 public static BigInteger probablePrime(int ...
- 与数论的爱恨情仇--01:判断大素数的Miller-Rabin
在我们需要判断一个数是否是素数的时候,最容易想到的就是那个熟悉的O(√n)的算法.那个算法非常的简单易懂,但如果我们仔细想想,当n这个数字很大的时候,这个算法其实是不够用的,时间复杂度会相对比较高. ...
- 记一次使用快速幂与Miller-Rabin的大素数生成算法
大家都知道RSA的加密的安全性就是能够找到一个合适的大素数,而现在判断大素数的办法有许多,比如Fermat素性测试或者Miller-Rabin素性测试,而这里我用了Miller-Rabin素性测试的算 ...
- POJ 1811 大素数判断
数据范围很大,用米勒罗宾测试和Pollard_Rho法可以分解大数. 模板在代码中 O.O #include <iostream> #include <cstdio> #inc ...
- HDU 4910 Problem about GCD 找规律+大素数判断+分解因子
Problem about GCD Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- 【算法编程】基于Miller-Rabin的大素数测试
基本原理: 费尔马小定理:如果p是一个素数,且0<a<p,则a^(p-1)%p=1. 利用费尔马小定理,对于给定的整数n,可以设计素数判定算法,通过计算d=a^(n-1)%n ...
- (Miller Rabin算法)判断一个数是否为素数
1.约定 x%y为x取模y,即x除以y所得的余数,当x<y时,x%y=x,所有取模的运算对象都为整数. x^y表示x的y次方.乘方运算的优先级高于乘除和取模,加减的优先级最低. 见到x^y/z这 ...
随机推荐
- Spark学习进度11-Spark Streaming&Structured Streaming
Spark Streaming Spark Streaming 介绍 批量计算 流计算 Spark Streaming 入门 Netcat 的使用 项目实例 目标:使用 Spark Streaming ...
- SDUST数据结构 - chap3 栈和队列
一.判断题: 二.选择题: 三.编程题: 7-1 一元多项式求导: 输入样例: 3 4 -5 2 6 1 -2 0 输出样例: 12 3 -10 1 6 0 代码: #include<bits/ ...
- merge join pg伪代码
Join { get initial outer and inner tuples INITIALIZE do forever { while (outer != inner) { SKIP_TEST ...
- redis 主从复制(一主两从)
一.环境基本信息 系统 centos7 版本 redis 5.0.7 只用了一台机器,ip:192.168.64.123 master端口 6379,从机 端口 6380.6381 二.redis目录 ...
- ichartjs测试dome分享
效果如下: 代码如下: <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> ...
- Py-面向对象,组合,继承
面向对象 只有特定对象能使用特定的几个方法对象=特征+动作 def dog(name,gender,type): #狗的动作 def jiao(dog): print('一条狗%s,汪汪汪' %dog ...
- Jmeter-插件扩展及性能监控插件的安装
需要对http服务进行大数据量的传值测试:看看产品中的http服务,能支持传多少字符:目标值是希望能到10w+: 上次测试中,服务器总是内存满导致服务不响应,因此想增加对服务端的性能监控:查阅了smi ...
- 基于源码分析Vue的nextTick
摘要:本文通过结合官方文档.源码和其他文章整理后,对Vue的nextTick做深入解析.理解本文最好有浏览器事件循环的基础,建议先阅读上文<事件循环Event loop到底是什么>. 一. ...
- SO_REUSEPORT 使用
https://www.cnblogs.com/Anker/p/7076537.html
- 文件夹copy器(多进程版)
import multiprocessing import os import time import random def copy_file(queue, file_name,source_fol ...