@概要 - 10ミラー - ラビン素数判定と因数分解ポラード-Rhoの@


@ 1-- primality_test_cost:ミラー・ラビンのアルゴリズム@

1.1 @ - アルゴリズムのソース@

我々は数xが素数である検出する必要がある場合は、私たちはどのようにすればよいですか?

最も明白には2〜N-1からのもう一つの要因xを見つけようとしています。
もちろん、それは少し最適化することがあります。ただ、〜2から√xを見て、アルゴリズムのこの複雑さはO(√x)です。

だから、何より良いアルゴリズムがありますか?一人でO(√x)アルゴリズムが適切から遠く離れている場合には暗号で数論は、使用していました。
より良い決定論的アルゴリズムは存在しないが、それはそれは、アルゴリズムの競争の中では適用されない、あまりにも複雑です。
我々としても、よりシンプルなデザインの方向変更される可能性があります乱択アルゴリズムを

検討フェルマーの小定理を:\
[pは素数、^ {P-1}である場合 = 1 \ MODのp \]

その逆定理である:
[{P-1} = ^場合\ 1つの\ MOD P、 次いで、pは素数である\]

この定理は必ずしも真実ではないが、高い確率の確立
私たちは、pが素数であるかどうかを判断するために、定理が確立したか否かを検出する、いくつかのAを選択するかもしれません。
だから、このアルゴリズムは正しい確率が非常に高いです。

いくつかの合成数X、aはすべてのために満足される-非常に合理的なようだが、\(X-A ^ {} = 1 1 \ MOD X \。)
以下の改善を使用する必要がありながら、我々は、さらに、この方法を改善する必要があり、二次プローブ定理:\
、pは素数である場合、[X ^ 2 = 1 \ MOD Pであれば 、 その後、X = 1またはp-1 \ MOD P \]

その逆定理である:
\ [もしx ^ 2 = 1 \ MOD P 、 及びX = 1またはp-1 \ MOD P、次いで、pは素数\]

この逆定理のような偉大な確率に設立
各複合数xに対して、2つの逆定理同時に上記を満たさないがなければならない、ことを示すことができます。

1.2 @ - アルゴリズム記述@

我々は、xの数を検出します。

私たちは、いくつかの素数A1、A2、...、AKを選択します。
最初のx = AI除外とxは速度にAIの倍数です。

Xよう- 1 = 2 ^ k個*の M、 mは奇数(即ち、抽出P - 2の1乗)です。
Xは、上記のように排出された偶数であるので、K> = 1。

次に、各AIのために再び次の手順を実行し、それを行う:
決定N0が= AI ^ M、またはケースN0 = 1つのP場合- 1成功したと見なさ検出します。
順次2 = n1は* N0、N2 =得る 2 * N1 = 2 ^ 2 * N0、...、NK = 2 ^ kの* N0。
順次N1〜NKをチェックします。NI = P場合NIのために、 - 1つの検出が成功したと考え、そうでない場合、NI場合= 1故障検出とみなし、最終NK≠1は、障害が検出されたと考えられる場合。

プロービング二次の両方を満たすために必要な検出の上に見つけることができますが、また、フェルマーの小定理の要件を満たすために、成功を検出します。

素数A1、A2、...、適切なAK。
X <= 10 ^ 12であれば、1662803に連れて行く{2、13、23}。
もしx <= 10 ^ 18、テイク{2、3、5、7、11、13、17、19、23}ができます。
それは得ることができますが、あまりにも多く、さらに精度を確保するが、あまりにも遅いです。

このアルゴリズムは、失敗は成功が保証されていない検出に失敗している必要があります検出します。それは、そのランダム性の嘘です。
しかし、データ範囲のアルゴリズムでの競争は、正確さを保証することができます。

1.3 @ - @アルゴリズム

アルゴリズムは非常に賢いです。

typedef long long ll;
const int prm[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
ll mul_mod(ll a, ll b, ll mod) {
    ll ret = 0;
    while( b ) {
        if( b & 1 ) ret = (ret + a)%mod;
        a = (a + a)%mod;
        b >>= 1;
    }
    return ret;
}
ll pow_mod(ll b, ll p, ll mod) {
    ll ret = 1;
    while( p ) {
        if( p & 1 ) ret = mul_mod(ret, b, mod);
        b = mul_mod(b, b, mod);
        p >>= 1;
    }
    return ret;
}
bool Miller_Rabin(ll x, ll y, ll z) {
    ll pw = pow_mod(y, z, x);
    if( pw == 1 || pw == x-1 ) return true;
    for(;z!=x-1;z<<=1) {
        pw = mul_mod(pw, pw, x);
        if( pw == x-1 ) return true;
        else if( pw == 1 ) return false;
    }
    return false;
}
bool Prime_Test(ll x) {
    for(int i=0;i<10;i++)
        if( x == prm[i] ) return true;
        else if( x % prm[i] == 0 ) return false;
    ll k = x-1;
    while( k % 2 == 0 ) k /= 2;
    for(int i=0;i<10;i++)
        if( !Miller_Rabin(x, prm[i], k) ) return false;
    return true;
}

2 @ - 因数分解:ポラード-Rhoのアルゴリズム@

2.0 @ - @参照

このセクションでは、このブログ記事を参照します

2.1 @ - アルゴリズムのソース@

一度は比較的優れたアルゴリズム、競争を促進するために使用されるアルゴリズムであるように素数の試験と同様に、ポラード・ロー+単純なアルゴリズムは、コードの組み合わせです。

Nが合成数である場合(ここでは素数判定はNが合成数であるかどうかをテストする必要があります)。
Pの存在<= Qおよびp≠1、を満たすN = P *は、Q。

我々は、乱数列{XI}を生成すること、X1 =ランド()、XI =ので、 F(XI-1)MOD N.
ある場合、私は、jを満たすにxi = xjのモッズpとXI≠XJのMODのN、その後、私たちも、このPを見つけます。
そして、Dを取る= GCD(XI - XJ、 N)はD Nの非自明な要因を見つけることができるようになります

我々は必ずしも円形断面である列{XI}から乱数を定義することに留意されたいです。そして誕生日パラドックスによれば、ループ部R1の所望の長さは、O(√N)です。
注文数列{YI} YI = XI MOD pは、{yiが}ループ部R2の予想される長さであるO(√p)であり、そしてR 1の要因です。
時点R1≠R2、我々は、上記の方法で非自明な因子Dを見つけることができます。

2.2 @ - アルゴリズム記述@

一般的に、我々は、F(X)を取る= X ^ランダムパラメータであり+ 2、。

我々は、xは[i]とX [2 * i]を取る(具体的には、Zを作る[I] = xで[2 * i]は、 次にZ [I + 1] = F (F(Z [I])))。
GCD(X [i]は- X場合 [2 * i]は、N)= 1、 次いで2 * I -私は=私は、サイクル部ない反復を続けます。
- (X X [i]はGCDはなら [2 * i]は、N)= N、 次に[I] = xとX [2 - * i]は、2 * I iは= I の場合、{xiは}セクションを循環しています反復を停止し、ランダムなパラメータが変化し、再びそれを行います。
それ以外の場合は、GCDは、(X [i]は- X [2 * i]を、N) 我々はその要因を探しているものです。

私たちは答えを得るためにO(√p)回を列挙する楽しみ、そしてp = O(√N)。
最終的な計算の複雑望ましく\(O(N ^ {\ FRAC {1} {4}} * \アルファ)\(N))であり、ここで\(\アルファ(N)は、\ ) GCDの複雑さです。

2.3 @ - @アルゴリズム

次のコードは、最小需要がプロセスの数倍であることを示しています。

実装上のいくつかの注目すべき細部はまだあります。

typedef long long ll;
const int INF = (1<<30);
const int prm[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
ll mul_mod(ll a, ll b, ll mod) {
    ll ret = 0;
    while( b ) {
        if( b & 1 ) ret = (ret + a)%mod;
        a = (a + a)%mod;
        b >>= 1;
    }
    return ret;
}
ll pow_mod(ll b, ll p, ll mod) {
    ll ret = 1;
    while( p ) {
        if( p & 1 ) ret = mul_mod(ret, b, mod);
        b = mul_mod(b, b, mod);
        p >>= 1;
    }
    return ret;
}
bool Miller_Rabin(ll x, ll y, ll z) {
    ll pw = pow_mod(y, z, x);
    if( pw == 1 || pw == x-1 ) return true;
    for(;z!=x-1;z<<=1) {
        pw = mul_mod(pw, pw, x);
        if( pw == x-1 ) return true;
        else if( pw == 1 ) return false;
    }
    return false;
}
bool Prime_Test(ll x) {
    for(int i=0;i<10;i++)
        if( x == prm[i] ) return true;
        else if( x % prm[i] == 0 ) return false;
    ll k = x-1;
    while( k % 2 == 0 ) k /= 2;
    for(int i=0;i<10;i++)
        if( !Miller_Rabin(x, prm[i], k) ) return false;
    return true;
}
ll gcd(ll x, ll y) {
    return y == 0 ? x : gcd(y, x%y);
}
ll abs(ll x) {
    return x < 0 ? -x : x;
}
ll min(ll x, ll y) {
    return x < y ? x : y;
}
ll Pollard_Rho(ll x) {
    for(int i=0;i<10;i++)
        if( x % prm[i] == 0 ) return prm[i];
    ll a = rand() % (x-2) + 2, b = a;
    ll c = rand() % (x-1) + 1, d = 1;
    while( d == 1 ) {
        a = (mul_mod(a, a, x) + c)%x;
        b = (mul_mod(b, b, x) + c)%x;
        b = (mul_mod(b, b, x) + c)%x;
        d = gcd(abs(a-b), x);
    }
    return d;
}
ll Find_Min_Div(ll x) {
    if( x == 1 ) return INF;
    if( Prime_Test(x) ) return x;
    ll y = Pollard_Rho(x);
    return min(Find_Min_Div(y), Find_Min_Div(x/y));
}

おすすめ

転載: www.cnblogs.com/Tiw-Air-OAO/p/11526893.html