대정 수 산술 패키지 (Java) 실현 (2)-빠른 전력 모듈러스, 최대 공약수, 곱셈 역 요소, 소수 판단, 큰 소수 생성

이전 블로그 구현 큰 정수 산술 패키지 (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의 곱셈 역을 찾습니다.
15 모듈로 41의 곱셈 역은 11입니다.

   /**
	 * 扩展欧几里得算法
	 */
	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 알고리즘에 대한 설명 :
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("合数");

연산 결과 : 소수

여섯, 소스 다운로드

Big Integer Package (Java) 구현

추천

출처blog.csdn.net/H_X_P_/article/details/104110639