その際GMPを使うと大きな桁数も扱えるとアドバイスをいただきましたので、
それを用いてソースコードを書き直しました。
今回はポラードのρ法を用いてレピュニットの因数分解をしようとしています。
レピュニットとはすべての桁が1である自然数のことです。
今回は1が53個並んだR(53)を因数分解するプログラムを組もうとしています。
ここまで正しく動作したとコメントアウトしてある箇所の後のループから抜け出せなくなっています。
原因は該当ループの2回目の V の値が期待するものと違うため、
そのあとの最大公約数が正しく求められず正常な動作をしないと考えています。
何かおかしな操作をしているか、足りていないものはあるか、
自力で見つけられなかったのでこちらに質問させていただきました。
ソースコードがかなり読みにくいとは思いますが、どうかお力添えください。
OS:Win7
コンパイラ:gcc
ライブラリ:GMP(The GNU MP Bidnum Library)
今回はCygwinを使用しています。
出力結果は
11111111111111111111111111111111111111111111111111111
= 107 * 1659431 * 1325815267337711173 * 47198858799491425660200071
となるのが正しいです。
以下にアルゴリズムとソースコードを示します。
nはユーザが入力する大きな桁数の整数です。
1[乱数種の選択]
ランダムにa∈[1,n-3]を選ぶ;
ランダムにs∈[0,n-1]を選ぶ;
U=V=s;
F(x)=(x * x + a) mod nと定める;
2[因子の探索]
U=F(U);
V=F(V);
V=F(V); //2回適用するのは意図的
g=gcd(U-V,n); //最大公約数を求める
if(g==1) goto [因子の探索];
3[乱数種が悪かった場合]
if(g==n) goto [乱数種の選択];
4[成功]
return g; //非自明な因子が見つかった
#include <stdio.h>
#include <stdlib.h>
#include <gmp.h>
#define BASE 10
int main()
{
int i,j,k;
mpz_t a;
mpz_t s;
mpz_t d;
mpz_t n;
mpz_t z;
mpz_t U;
mpz_t V;
mpz_t rnd;
mpz_t temp;
gmp_randstate_t rstate;
mpz_init(a);
mpz_init(s);
mpz_init(d);
mpz_init(n);
mpz_init(z);
mpz_init(U);
mpz_init(V);
mpz_init(rnd);
mpz_init(temp);
gmp_randinit_default(rstate);
mpz_set_str(n,"11111111111111111111111111111111111111111111111111111",BASE);
//Repunit R(53)
gmp_printf("%Zd \n= ",n);
mpz_sub_ui(n,n,3); //n=n-3
mpz_urandomm(rnd,rstate,n);//0<rnd<(n-3)-1
mpz_add_ui(a,rnd,1); //a=rnd+1 == 1<a<n-3
mpz_add_ui(n,n,4); //n=n+4
mpz_urandomm(rnd,rstate,n);//0<rnd<(n+4)-1
mpz_set(s,rnd); //s = rnd == 0<s<n
mpz_set(U,s); //U=s
mpz_set(V,s); //V=s
mpz_sub_ui(n,n,1); //(n=n-1)
while(1){//2
mpz_mul(temp,U,U); //temp = U * U
mpz_mul(temp,temp,a); //temp = temp * a
mpz_cdiv_r(U,temp,n); // U = temp % n
mpz_mul(temp,V,V); //temp = V * V
mpz_mul(temp,temp,a); //temp = temp * a
mpz_cdiv_r(V,temp,n); // V = temp % n
mpz_mul(temp,V,V); //temp = V * V
mpz_mul(temp,temp,a); //temp = temp * a
mpz_cdiv_r(V,temp,n); // V = temp % n
mpz_sub(temp,U,V); // temp = U - V
mpz_gcd(d,temp,n); // d = gcd(temp,n);
i = mpz_cmp_ui(d,1); //
if(i<=0)
continue; //loop until d > 1
break;
}//2
gmp_printf(" %Zd ",d);
while(1){//3
j=mpz_cmp(n,d);
if(j<=0) break; //if(n > d) break;
mpz_cdiv_q(n,n,d); //n = n / d
mpz_sub_ui(n,n,3); //n = n - 3
mpz_urandomm(rnd,rstate,n);
mpz_add_ui(a,rnd,1); //a = rnd + 1
mpz_add_ui(n,n,4); //n = n + 4
mpz_urandomm(rnd,rstate,n);
mpz_set(s,rnd); //s = rnd
mpz_set(U,s); //U = s
mpz_set(V,s); //V = s
mpz_sub_ui(n,n,1); //n = n - 1
//ここまでは正しく動作した
while(1){//2
mpz_mul(temp,U,U); //temp = U * U
mpz_mul(temp,temp,a); //temp = temp * a
mpz_cdiv_r(U,temp,n); // U = temp % n
mpz_mul(temp,V,V); //temp = V * V
mpz_mul(temp,temp,a); //temp = temp * a
mpz_cdiv_r(V,temp,n); // V = temp % n
mpz_mul(temp,V,V); //temp = V * V
mpz_mul(temp,temp,a); //temp = temp * a
mpz_cdiv_r(V,temp,n); // V = temp % n
mpz_sub(temp,U,V); // temp = U - V
mpz_gcd(d,temp,n); // d = gcd(temp,n);
k = mpz_cmp_ui(d,1); //
if(k<=0)
continue; //loop until d > 1
break;
}//2
gmp_printf("* %Zd ",d);
}//3
mpz_clear(a);
mpz_clear(s);
mpz_clear(d);
mpz_clear(n);
mpz_clear(z);
mpz_clear(U);
mpz_clear(V);
mpz_clear(rnd);
mpz_clear(temp);
return 0;
}