大素數判斷和分解

用Miller-Rabin算法進行大素數判斷以及Pollard-rho算法進行分解的模版

ll pri[]={2,7,61};//用小素數表做隨機種子可避免第一類卡米歇爾數的誤判 
/*
if n < 1,373,653, it is enough to test a = 2 and 3;
if n < 9,080,191, it is enough to test a = 31 and 73;
if n < 4,759,123,141, it is enough to test a = 2, 7, and 61;
if n < 1,122,004,669,633, it is enough to test a = 2, 13, 23, and 1662803;
if n < 2,152,302,898,747, it is enough to test a = 2, 3, 5, 7, and 11;
if n < 3,474,749,660,383, it is enough to test a = 2, 3, 5, 7, 11, and 13;
if n < 341,550,071,728,321, it is enough to test a = 2, 3, 5, 7, 11, 13, and 17.
*/
ll ans[100005],flag;//ans數組記錄分解質因數的結果,flag記錄質因數的個數,相同的質因數不合並! 
ll gcd(ll a,ll b)//非遞歸,遞歸的對大數易爆棧
{
        while(b)
        {
                ll c=a%b;
                a=b;
                b=c;
        }
        return a;
} 
ll multi(ll a,ll b,ll n)//乘法快速冪
{
        ll tmp=0;
        while(b){
                if(b&1){
                        tmp+=a;
                        if(tmp>=n)
                                tmp-=n;
                }
                a<<=1;
                if(a>=n)a-=n;
                b>>=1;
        }
        return tmp;
}
ll multimod(ll a,ll m,ll n)//乘方快速冪
{
        ll tmp=1;
        a%=n;
        while(m)
        {
                if(m&1) tmp=multi(tmp,a,n);
                a=multi(a,a,n);
                m>>=1;
        }
        return tmp;
}
bool Miller_Rabin(ll n)//大數判斷
{
        if(n<2)
                return false;
        if(n==2)
                return true;
        if(!(n&1))
                return false;
        ll k=0,i,j,m,a;
        m=n-1;
        while(!(m&1)) m>>=1,k++;
        for(i=0;i<3;i++)
        {
                if(pri[i]>=n)
                        return true;
                a=multimod(pri[i],m,n);
                if(a==1) continue;
                for(j=0;j<k;j++)
                {
                        if(a==n-1)
                                break;
                        a=multi(a,a,n);
                }
                if(j==k)
                        return false;
        }
        return true;
}
ll pollard_rho(ll c,ll n)//尋找因數
{
        ll i,x,y,k,d;
        i=1;
        x=y=rand()%n;
        k=2;
        do{
                i++;
                d=gcd(n+y-x,n);
                if(d>1&&d<n)
                        return d;
                if(i==k) y=x,k<<=1;
                x=(multi(x,x,n)+n-c)%n;
        }while(y!=x);
        return n;
}
void rho(ll n)//遞歸分解
{
        if(Miller_Rabin(n))
    {
        ans[flag]=n;
        flag++;
        return;
    }
        ll t=n;
        while(t>=n)//這一步是找出一個因數並存入t中,注意找出的因數沒有任何確定的大小順序
                t=pollard_rho(rand()%(n-1)+1,n);
        rho(t);
        rho(n/t);
        return;
}
int main()
{
    ll n,i;
    flag=0;//質因數的個數必須初始化 
    scanf("%I64d",&n);
    rho(n);//分解出n的所有質因數存入ans數組 
    for(i=0;i<flag;i++)printf("%I64d ",ans[i]);//顯示結果 
    printf("\n");
    return 0;    
} 
發佈了35 篇原創文章 · 獲贊 10 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章