素数判定算法 MILLER RABIN

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了素数判定算法 MILLER RABIN相关的知识,希望对你有一定的参考价值。

入门级筛素数--试除法,复杂度O(n^2)

bool rmprime( long long n )
{
    for(long long i = 2; i <= sqrt(n) ; i++)    if(n%i == 0) return false;
    return true;
}

 

学了一段时间算法以后,应该会了解到筛法求素数,复杂度略高于O(n)

#include<iostream>
#include<cstring>
using namespace std;
const int MAXN = 500000;
bool isp[MAXN];
int p[MAXN];
int cnt = 0;//保存素数个数
void getp()
{
    for(int i = 1; i < MAXN; i++)    isp[i] = 1 ; //默认全部素数
    for(int i = 2; i < MAXN; i++){
        if(!isp[i]) continue; //如果不是素数就continue掉
        p[cnt++] = i;
        for(int j = i * 2 ; j < MX; j += i)        isp[j] = 0;//记录,往后滚处理
    }
}

int main(){
    getp();
    for(int i = 0; i < cnt; i++)    printf("%d ",p[i]);
        return 0;      
}

 当然,不难发现,如果MaX值过大的话,不只空间会炸,而且从头开始扫很玄学,是不怎么可取的。

于是引入MILLER RABIN算法。可以单独判断一个大数是否素数,但是不保证正确。我们只能通过多次执行算法让这个错误的概率很小。//不过幸运的是,除非你是非酋王,这个算法一般都是不会出问题的。

算法的理论基础:
1. Fermat定理:若n是奇素数,a是任意正整数(1≤ a≤ n?1),则 a^(n-1) ≡ 1 mod n。
2. 推演自Fermat定理(具体过程我没看懂,Orz), 如果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 成立。
 
聪明的读者已经发现上述的定理是一个数是素数的必要条件而非充分条件,所以这就是这个算法的不精确的原有,对于一些特定的检验算子a,存在一些合数也满足上述定理。所以我们要多找几个a反复检验,这样能让错误率大大降低。
 
那么我们按照上述的定理2,首先重复n次实验。对于每一次实验,随机取检验算子a,带入定理2进行检验,看看在算子a下,n能否满足
a^r ≡ 1 mod n或者对某个j (0 ≤ j≤ s?1, j∈Z) 等式a^(2jr) ≡ ?1 mod n       **
如果任意一次实验不满足,则判定不是素数,如果都满足,可近似可以认为是素数(错误率极小)。
 
#include <iostream> 
#include <cstdio> 
#include <algorithm>  
#include <cmath>  
#include <cstring>  
#include <map>  
using namespace std;

const int times = 20;
int number = 0;

map<long long, int>m;
long long Random( long long n )            //生成[ 0 , n ]的随机数
{
    return ((double)rand( ) / RAND_MAX*n + 0.5);
}

long long q_mul( long long a, long long b, long long mod ) //快速计算 (a*b) % 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 ) //快速计算 (a^b) % 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;
}

bool witness( long long a, long long n )//miller_rabin算法的精华
{//用检验算子a来检验n是不是素数
    long long tem = n - 1;
    int j = 0;
    while(tem % 2 == 0)
    {
        tem /= 2;
        j++;
    }
    //将n-1拆分为a^r * s

    long long x = q_pow( a, tem, n ); //得到a^r mod n
    if(x == 1 || x == n - 1) return true;    //余数为1则为素数
    while(j--) //否则试验条件2看是否有满足的 j
    {
        x = q_mul( x, x, n );
        if(x == n - 1) return true;
    }
    return false;
}

bool miller_rabin( long long n )  //检验n是否是素数
{

    if(n == 2)
        return true;
    if(n < 2 || n % 2 == 0)
        return false;                //如果是2则是素数,如果<2或者是>2的偶数则不是素数

    for(int i = 1; i <= times; i++)  //做times次随机检验
    {
        long long a = Random( n - 2 ) + 1; //得到随机检验算子 a
        if(!witness( a, n ))                        //用a检验n是否是素数
            return false;
    }
    return true;
}


int main( )
{
    long long tar;
    while(cin >> tar)
    {
        if(miller_rabin( tar ))    //检验tar是不是素数
            cout << "Yes, Prime!" << endl;
        else
            cout << "No, not prime.." << endl;
    }
    return 0;
}

 

 

以上是关于素数判定算法 MILLER RABIN的主要内容,如果未能解决你的问题,请参考以下文章

10^9以上素数判定,Miller_Rabin算法

Miller-Rabin算法 codevs 1702 素数判定 2

数学#素数判定Miller_Rabin+大数因数分解Pollard_rho算法 POJ 1811&2429

Miller-Rabin素性判定算法

python Miller Rabinの素数判定法

Miller_Rabin(米勒拉宾)素数测试