목차
이전 블로그 구현 큰 정수 산술 패키지 (Java) (1)-덧셈, 뺄셈, 곱셈, 나눗셈, 모듈로 모드, 모듈 덧셈 (음수로 간주) , 우리는 많은 수의 기본 덧셈, 뺄셈, 곱셈, 나누고 나머지를 취하십시오. 이 블로그는 빠른 전력 계수 , 최대 공약수 , 곱셈 역 요소 , 소수 결정 및 큰 소수 생성 을 달성하기 위해 이들을 기반으로합니다 .
1. 빠른 전력 계수
우리가 2 계산할 경우 100 모드 (19), 가장 쉬운 방법은 99 곱셈 다음 모듈 (19)을하는 것입니다.
그러나 이것은 두 가지 문제가있을 것입니다 .1. 항상 곱셈을하는 데 시간이 많이 걸릴 것입니다 .2. 수는 결국 매우 커지고 저장하기 어려워
질 것입니다. 그래서 우리는 빠른 지수화 계수 (이진법과 유사)를 사용할 것이므로 7 번 계산합니다. 그게 다야.
그중에서도 우리가 얻는 숫자가 그리 크지 않도록 다음 두 가지 공식을 사용할 것입니다.
/**
* 快速幂取模
* @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 개조 7 = 4
2 10 개조 13 = 10
2 100 개조 19 = 17
2 1000 개조 1777 = 1775
2 10000 개조 49,999 = 100
2 100000 개조 = 998,111 802,658
둘째, 최대 공약수 (Euclidean 알고리즘)
유클리드의 알고리즘을 사용하여 던지기 및 나누기 방법이라고도하는 최대 공약수를 찾을 수 있습니다.
이제 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≡1 mod p 및 GCD (a, p) = 1 (a와 p가 상대적으로 소수 임)이면 모듈로 p에 대한 a의 곱셈 역을 b라고합니다.
이제 확장 된 유클리드 알고리즘을 사용하여 15 모듈로 41의 곱셈 역을 찾습니다.
/**
* 扩展欧几里得算法
*/
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 모듈로 108 곱하기 역 요소 = 95119
모듈로 4399 곱하기 역 요소 = 1109
49999 모듈로 1234567 곱하기 역 요소 = 1078243
넷째, 소수 결정 (Miller Robin 알고리즘)
Miller-Robin 알고리즘에 대한 설명 :
숫자가 소수인지 아닌지 를 판단하는 알고리즘 은 대략 다음과 같습니다.
여기에서 알고리즘의 power-modulus 알고리즘이 제대로 선택되지 않으면 전체 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 소수가 큰 소수를 생성)
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("合数");
연산 결과 : 소수