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

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

算法的理论基础:

  1. Fermat定理:若n是奇素数,a是任意正整数(1≤ a≤ n?1),则 a^(n-1) ≡ 1 mod n。

2.  如果n是一个奇素数,将n?1表示成2^s*r的形式,r是奇数,a与n是互素的任何随机整数,那么a^r ≡ 1 mod n或者对某个j (0 ≤ j≤ s?1, j∈Z) 等式a^(2jr) ≡ ?1 mod n 成立。

实验需要根据这个算法的理论来实现对素数的判定功能,而我将上述理论用C++的 形式写了出来,然后在一些细节的算法上少做润色,成功实现了对素数的生成和判定。

一、实验代码:

#include<iostream>

#include<cmath>

#include<ctime>

#include<cstdlib>

using namespace std;

typedef unsigned long long ll;

long long q_mul( long long a, long long b, long long mod )

{

long long ans = 0;

while(b)

{

if(b & 1)

{

b--;

ans =(ans+ a)%mod;

}

b /= 2;

a = (a + a) % mod;

}

return ans;

}

long long q_pow( long long a, long long b, long long mod )

{

long long ans = 1;

while(b)

{

if(b & 1)

{

ans = q_mul( ans, a, mod );

}

b /= 2;

a = q_mul( a, a, mod );

}

return ans;

}

//long long q_pow(ll a,ll b,ll mod){

// ll base=a;

// ll ans = 1;

// while(b!=0){

// if(b&1) ans = (ans*base)%mod;

// base = (base*base)%mod;

// b>>=1;

// }

// return ans;

//}

int Miller_Rabin(ll n) {

if(n<2) return 0;

if(n==2) return 1;

ll k=0,q=n-1;

while(q%2==0){

q=q/2;

k++;

}

ll a = rand(); //要保证a在(1,n-1)之间,开区间

a=(a%(n-2))+2;

ll result1 = q_pow(a,q,n);

if(result1 == 1||result1 == n-1){

return 1;

}

while(k--){

result1 = q_mul(result1,2,n);

if(result1 == n-1) return 1;

}

return 0;

}

bool True_Miller_Rabin(ll n){

int times = 10;

while(times){

times--;

if(Miller_Rabin(n)==0) return false;

}

return true;

}

int main()

{

srand((unsigned)time(NULL));

ll num;

// while(1){

// cin>>num;

// if(Miller_Rabin(num)==1)

// cout<<"为素数"<<endl;

// else{

// cout<<"是合数"<<endl;

// }

// }

for(ll i=1000000;i<=1005000;i++){

int a =0;

if(True_Miller_Rabin(i)){

cout<< i<<"是素数"<<endl;

}

}

return 0;

}

二、实验结果(自行测试)

这是对1000000000000000000到1000000000000005000里所有素数判定的结果

这是对输入素数的判读

以上结果说明,该程序完全能够胜任在long long类型范围下的素数判定任务。

三、实验总结

本次实验采用了Miller-Rabin算法,而在理解算法的基础上我们要灵活运用。在算法中我最开始用到了C++函数里面的pow函数,然而这个函数导致我素数输出不完整,经过很久的调试,我发现是C++自带库里面的数据类型与long long类型有出入,所以我放弃了使用自带的函数库。之后,我选择了快速幂算法。这个算法比pow函数效果更好,能够对大数进行快速的幂计算。然而在快速幂计算的过程中设计到两个数相乘,当两个Long 类型的数据相乘时会溢出从而导致计算的大素数长度有限。于是我有考虑将幂计算里面的乘法分成若干个加法去进行运算,于是我采用了快速乘与快速幂想结合的方式,也就是我上述代码中绿色的部分(蓝色部分为单纯快速幂),由此我讲幂运算的速度有提升了一个档次,在此基础上也增大了计算素数的范围。

——————Made By Pinging、、、、、hhh  Welcome to CUMT。。。

时间: 2024-11-05 13:48:54

记一次使用快速幂与Miller-Rabin的大素数生成算法的相关文章

快速幂取余算法

下面是一个快速幂的介绍: 先贴一个秦九韶算法(Horner算法)的原理: 设有项的次函数 将前项提取公因子,得 再将括号内的前项提取公因子,得 如此反复提取公因子,最后将函数化为 令 ...... 则即为所求 下面是讲解快速幂的:(By  夜せ︱深   感谢作者) 快速幂取模算法 在网站上一直没有找到有关于快速幂算法的一个详细的描述和解释,这里,我给出快速幂算法的完整解释,用的是C语言,不同语言的读者只好换个位啦,毕竟读C的人较多~ 所谓的快速幂,实际上是快速幂取模的缩写,简单的说,就是快速的求

OI模板(3)—— 快速幂(fast_power)

又是一个赤裸裸的模板,倍增思想其实是关键,我们只有稍加改动,也可以得出另外一种运算,快速乘,但实用性不如快速幂,大概只有在大整数乘法时才会用到 而倍增思想并不是仅仅用于快速运算,倍增求lca也是常用的倍增算法 #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath>

relays 奶牛接力跑(矩阵快速幂求最短路径)

题干: FJ的N(2<=N<=1,000,000)头奶牛选择了接力跑作为她们的日常锻炼项目.至于进行接力跑的地点 自然是在牧场中现有的T(2 <= T <= 100)条跑道上.农场上的跑道有一些交汇点,每条跑道都连结了两个不同的交汇点 I1_i和I2_i(1<=I1_i<=1,000; 1<=I2_i<=1,000).每个交汇点都是至少两条跑道的端点. 奶牛们知道每条跑道的长度length_i(1<=length_i<=1,000),以及每条跑道

蟠桃记《快速幂》(两种解法)

这道题比较容易所以解法也并不唯一.但是我们主要通过这道题讲解快速幂的算法. 题目如下: 喜欢西游记的同学肯定都知道悟空偷吃蟠桃的故事,你们一定都觉得这猴子太闹腾了,其实你们是有所不知:悟空是在研究一个数学问题! 什么问题?他研究的问题是蟠桃一共有多少个! 不过,到最后,他还是没能解决这个难题,呵呵^-^ 当时的情况是这样的: 第一天悟空吃掉桃子总数一半多一个,第二天又将剩下的桃子吃掉一半多一个,以后每天吃掉前一天剩下的一半多一个,到第n天准备吃的时候只剩下一个桃子.聪明的你,请帮悟空算一下,他第

2017省夏令营Day7 【快速幂,筛法,矩阵快速幂,线段树】

题解:首先,我们可以得到一个规律:经过2次变换后,a和b的值都分别乘2了,所以只要用快速幂就能过啦,但是,要特判n为0的情况. 代码如下: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #define Mod 1000000007 5 using namespace std; 6 long long a,b,n,ans1,ans2; 7 long long power(long long x)

快速幂 x

快速幂! 模板如下: 1 #include<iostream> 2 #include<cmath> 3 #include<cstdio> 4 5 using namespace std; 6 7 int b,p,k; 8 9 int fastpow(int a,int b) 10 { 11 int r=1; 12 int base=a; 13 while(b!=0) 14 { 15 if(b%2!=0)//奇次幂 16 r=r*base; 17 base=base*ba

【66测试20161115】【树】【DP_LIS】【SPFA】【同余最短路】【递推】【矩阵快速幂】

还有3天,今天考试又崩了.状态还没有调整过来... 第一题:小L的二叉树 勤奋又善于思考的小L接触了信息学竞赛,开始的学习十分顺利.但是,小L对数据结构的掌握实在十分渣渣.所以,小L当时卡在了二叉树. 在计算机科学中,二叉树是每个结点最多有两个子结点的有序树.通常子结点被称作“左孩子”和“右孩子”.二叉树被用作二叉搜索树和二叉堆.随后他又和他人讨论起了二叉搜索树.什么是二叉搜索树呢?二叉搜索树首先是一棵二叉树.设key[p]表示结点p上的数值.对于其中的每个结点p,若其存在左孩子lch,则key

51nod 1537 分解(矩阵快速幂)

分析:先写出前几项,发现都是有解的.记(1+√2)^n=a+b√2,可以归纳证明,当n为奇数时,m=a^2+1,n为偶数时,m=a^2.写出a的递推式,用矩阵快速幂算一下a即可. 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 const int p=1e9+7; 6 typedef unsigned long long ull; 7 ull mat

HDU 2276 &amp; FZU 1692 (循环同构优化+矩阵快速幂)

HDU 2276 题意: 给定一个01**字符串环**(2<=字符串长度<=100)然后进行m次的变换. 定义变换的规则为:如果当前位置i的左边是1(下标为0的左边是n-1),那么i就要改变状态0->1 , 1->0 比如当前的状态为100101那么一秒过后的状态为010111. 思路: 用公式表示变化状态其实就是: ai=(a(i+n?1)%n+ai)%2 换成位操作就是: ai=a(i+n?1)%n^ ai 于是我们可以建立一个变化矩阵: ??????????1100...00