目次
以前のブログでは、大きな整数演算パッケージ(Java)を実装しました(1)-加算、減算、乗算、除算、モジュロモード、モジュラー加算(負と見なされます)、多数の基本的な加算、減算、乗算、割り算、残りを取りなさい。このブログは、それらに基づいて、高速べき係数、最大公約数、乗法逆元、素数決定、および大きな素数の生成を実現します。
1.高速パワーモジュラス
2 100 mod 19 を計算する場合、最も簡単な方法は、99回の乗算を行ってから19を法とすることです。
しかし、これには2つの問題があります。1。常に乗算を行うには時間がかかります。2。数値は最終的に非常に大きくなり、格納が困難に
なるため、高速なべき乗係数(バイナリ法と同様)を使用するため、7回カウントしますそれでおしまい。
その中でも、次の2つの式を使用するため、取得される数はそれほど多くありません。
/**
* 快速幂取模
* @param one 底数
* @param two 指数
* @param mod 模
* @return 结果
*/
public static String Power(String one,String two,String mod) {
if(two.equals("0")) {
//0次幂结果为1
//System.out.println("Power result=1");
return "1";
}else if(two.equals("1")){
//1次幂结果为它本身
return Mod(one, mod);
}
String count=two,result="1",temp=one;
while(!count.equals("0")){
if(Mod(count, "2").equals("1")) //看它二进制最后一位是不是1
result=Multiply(result, temp, mod);
if(!count.equals("1")) //这里避免最后一次做没用的乘法
temp=Multiply(temp, temp, mod);
count=Division(count, "2"); //次数减1,相当于二进制右移一位
}
//System.out.println(result);
return result;
}
演算結果:
2 5 mod 7 = 4
2 10 mod 13 = 10
2 100 mod 19 = 17
2 1000 mod 1777 = 1775
2 10000 mod 49999 = 100
2 100000 mod 998111 = 802658
第二に、最大公約数(ユークリッドアルゴリズム)
ユークリッドのアルゴリズムを使用して、最大の公約数を見つけることができます。これは、トスおよび分割法としても知られています。
次に、52と36の最大公約数を見つけます。
剰余が0の場合、現在の数式の約数が最大公約数になります。
/**
* 最大公约数
* @param one
* @param two
* @return 结果
*/
public static String GCD(String one,String two) {
if(one.equals(two)) {
//相等则GCD=任意一个
//System.out.println("GCD="+one);
return one;
}
int length1=one.length();
int length2=two.length();
String first=null,second=null,temp=null;
if(length1>length2) {
//保证第一个数大于第二个,当然也可以不用这么做
first=one;
second=two;
}else if(length1<length2) {
first=two;
second=one;
}else {
for (int i = 0; i < length1; i++) {
if(one.charAt(i)>two.charAt(i)) {
first=one;
second=two;
break;
}
else if(one.charAt(i)<two.charAt(i)) {
first=two;
second=one;
break;
}
}
}
while(!second.equals("0")) {
temp=Mod(first, second);
first=second;
second=temp;
}
//System.out.println("GCD="+first);
return first;
}
3、乗法逆元(拡張ユークリッドアルゴリズム)
ab≡1mod pでGCD(a、p)= 1(aとpは比較的素数)の場合、pを法とするaのaの乗法逆数はbと呼ばれます。
次に、拡張ユークリッドアルゴリズムを使用して、41を法とする15の逆数を求めます。
/**
* 扩展欧几里得算法
*/
static String x= "0",y= "0";
public static String ExtendGCD(String a,String b) {
if(b.equals("0")) {
Operation.x="1";
Operation.y="0";
return a;
}
String d=ExtendGCD(b, Mod(a, b));
String temp=Operation.x;
Operation.x=Operation.y;
Operation.y=Subtract(temp, Multiply(Division(a, b), Operation.y));
//System.out.println(" "+Operation.x);
//System.out.println(" "+Operation.y);
return d;
}
/**
* 乘法逆
* @param a
* @param mod
* @return
*/
public static String MultiplicativeInverse(String a,String mod) {
String d=ExtendGCD(a,mod);
if(d.equals("1"))
return Add(Mod(Operation.x, mod), mod, mod);
return "-1"; //没有逆元
}
演算結果:
5を法とする23乗法逆元= 14
28を法とする75乗法逆要素= 67
83を法とする乗法逆要素= 95
119が法4399乗法逆要素= 1109
49999法1234567乗法逆要素= 1078243
4番目に、素数決定(Miller Robinアルゴリズム)
ミラーロビンアルゴリズムの説明:
数値が素数かどうかを判断するためのアルゴリズムは、おおよそ次のとおりです。
ここで、アルゴリズムのパワーモジュラスアルゴリズムが適切に選択されていないと、ミラーロビンアルゴリズム全体に非常に恐ろしい時間がかかることを言いたいです...
/**
* 米勒罗宾算法
* @param one
* @return
*/
public static boolean MillerRabin(String one) {
if(one.equals("0")||one.equals("1")) //0和1不是素数
return false;
if(one.equals("2")) //2是素数
return true;
if((one.charAt(one.length()-1)-48)%2==0) //偶数不是素数
return false;
String number=Subtract(one, "1"); //计算n-1
String number1=number;
int count=0;
while((number1.charAt(number1.length()-1)-48)%2==0) {
//n-1=m*2^t
number1=Division(number1, "2");
count++;
}
for(int i=1;i<=5;i++) {
//(a^(n-1))%n=(a^(m*2^t))%n
String random=String.valueOf(i+2);
String x=Power(random, number, one); //(a^m)%n
String y="";
for(int j=1;j<=count;j++) {
//((a^m)^(2^t))%n
y=Multiply(x, x, one);
if(y.equals("1")&&!x.equals("1")&&!x.equals(number)) //如果不满足二次探测定理,则不是素数
return false;
x=y;
}
if(!y.equals("1")) //如果不满足费马小定理,则不是素数
return false;
}
return true;
}
演算結果:
111561511は複合数
564765326677は素数
49841516591656517は複合数
555469971929450687843は素数
262314699260834231863164359738235486290658375509は素数
892209251968203592191654785870096688160362184103664355853918147486564850331は素数
五、生成大素数
/**
* 生成素数算法
* @return 素数
*/
public static String PrimeGeneration() {
//一般来说,整除100以内的所有素数可排除76%不是素数的可能性,整除256以内的所有素数可排除80%
//不是素数的可能性,所以创建小素数表,可以大幅加快速度,当然这个表可以手动生成
String[] table= {
"3","7","11","13","17","19","23","29","31","37","41","43","47",
"53","59","61","67","71","73","79","83","89","97","101","103","107","109",
"113","127","131","137","139","149","151","157","163","167","173","179",
"181","191","193","197","199","211","223","227","229","233","239","241",
"251","257","263","269","271","277","281","283","293","307","311","313",
"317","331","337","347","349","353","359","367","373","379","383","389",
"397","401","409","419","421","431","433","439","443","449","457",
"461","463","467","479","487","491","499"};
Random random=new Random();
int flag;
long time1=System.currentTimeMillis();
while(true) {
String number="";
for(int i=1;i<=33;i++) //生成一个随机的大奇数,这个位数任意取
number+=String.valueOf(random.nextInt(899999998)+100000001);
System.out.println(number);
int num=random.nextInt(800)+101; //后三位
if(num%2==0) //跳过偶数
num++;
for(int i=1;i<=50;i++,num+=2) {
//搜索附近的50个奇数
String temp="";
if(num%5==0) //跳过5的倍数
num+=2;
temp=temp+number+String.valueOf(num);
flag=0;
for(int j=0;j<table.length;j++) {
if(Mod(temp, table[j]).equals("0")) {
//看能不能被小整数整除
flag=1;
break;
}
}
if(flag==1)
continue;
else
if(MillerRabin(temp)) {
//米勒罗宾算法
System.out.println("素数: "+temp);
System.out.println("时间差="+(System.currentTimeMillis()-time1)+"ms");
return temp;
}
}
}
}
演算結果(大きな素数を生成する300 10進数):
955042930633410289133616296687431777269353980956568253574985061454859846383784618868936295454149058329055354262839296541908590329891268218404276396709186373481902442299599349413886590143757678944807286223232776732690994758060943148907454012806238319657554857310557054678934303822406793932126613431907が素数である
時間差369529ms =
886561163228838664750509032768759020351470065461506216295171421466522603290150530199373404129571069480539452635354057998985307892246327624821492158196842621382357442511837684610582698182410676560942977011624164506742932167839443913503332061016760221262755081522835308001246894308971214499396769460513が素数である
時間差= 29439ms
214870052980815367577291784627902708719802277128149369356311939236596853366271103968812931332145864571367016263259506949201985903708991330657005820918132219051420306215369688007649436101361885347977415827831904465125972681277283243530766501893543832374257674319643447978284232131374047798140761172317は素数である
時間差143827ms
生成された大きな素数については、以前に記述したMiller Robinアルゴリズムを使用して検出できます。もちろん、JavaのBigIntegerクラスを使用して判断することもできます(このクラスを使用して、大きな素数を非常に迅速に生成します。興味がある場合は、それを調べることができます)。
String string="955042930633410289133616296687431777269353980956568253574985061454859846383784618868936295454149058329055354262839296541908590329891268218404276396709186373481902442299599349413886590143757678944807286223232776732690994758060943148907454012806238319657554857310557054678934303822406793932126613431907";
BigInteger a=new BigInteger(string);
if(a.isProbablePrime(1024)) a是素数的概率为1 - 1 / 2^1024
System.out.println("素数");
else
System.out.println("合数");
演算結果:素数