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这 ...
随机推荐
- jenkins 构建历史 显示版本号
0 jenkins 安装此插件: 此插件名为 " groovy postbuild " 1 效果图: 2 安装插件: 系统管理 --> 插件管理 --> 可选 ...
- TCP/IP协议栈在Linux内核中的运行时序分析
网络程序设计调研报告 TCP/IP协议栈在Linux内核中的运行时序分析 姓名:柴浩宇 学号:SA20225105 班级:软设1班 2021年1月 调研要求 在深入理解Linux内核任务调度(中断处理 ...
- HashMap为什么效率高?来看看这个小demo
一.前情回顾:在程序中有时候需要存放对象,容器应运而生.容器分为集合和Map.集合在这里不说,说说Map.Map在英语中是地图的意思,这个名字真是起的好,可以让人顾名思义.Map,就是存放键值对的结构 ...
- 【TOMCAT】windows7下tomcat6环境部署
首先,下载一个tomcat6的部署包 地址http://download.csdn.net/download/imliuqun123/10156942 需要部署安装的win7环境变量: 1.jdk环境 ...
- Pandas的数据分组-aggregate聚合
在对数据进行分组之后,可以对分组后的数据进行聚合处理统计. agg函数,agg的形参是一个函数会对分组后每列都应用这个函数. import pandas as pd import numpy as n ...
- 面向对象的延伸与Java内部定义类的应用
识别类 传统的过程化程序设计,必须从顶部的main函数开始编写程序,在面向对象程序设计时没有所谓的"顶部".首先从设计类开始,然后再往每个类中添加方法. 识别类的规则是在分析问题的 ...
- WinForm中实现按Enter将光标移动到下一个文本框
首先窗体加载出来是上面这个样子.有五个文本框,我们要实现的功能就是输入姓名后按Enter,使光标直接定位到手机号中. 在页面加载的时候我们就要获取所有文本框控件,并添加回车事件 private voi ...
- Linux 技巧:让进程在后台运行更可靠的几种方法
Linux 技巧:让进程在后台运行更可靠的几种方法 https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/index.html 我们经常会碰到这 ...
- MySQL的索引为什么用B+Tree?InnDB的数据存储文件和MyISAM的有何不同?
前言 这篇文章的题目,是我真实在面试过程中遇到的问题,某互联网众筹公司在考察面试者MySQL相关知识的第一个问题,我当时还是比较懵的,没想到这年轻人不讲武德,不按套路出牌,一般的问MySQL的相关知识 ...
- Prometheus监控Kafka
Prometheus监控Kafka 1.Prometheus监控Kafka,Docker方式 Kafka监控优秀博文: 简书:whaike:[监控]Kafka - 详细指标 CSDN:GeekXuSh ...