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

Posted Pinging_Goooooo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次使用快速幂与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在(1n-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;

}

   

 

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

 

这是对10000000000000000001000000000000005000里所有素数判定的结果

 

 

这是对输入素数的判读

 

 

 

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

 

 

 

 

三、实验总结

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

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

 

以上是关于记一次使用快速幂与Miller-Rabin的大素数生成算法的主要内容,如果未能解决你的问题,请参考以下文章

Miller-Rabin与二次探测

浅谈Miller-Rabin素数检测算法

Miller-Rabin?素数测试算法

Miller-Rabin素数测试

Miller-Rabin随机判素数算法

Miller-Rabin 素数测试