经典算法(4)- 用欧几里得算法实现扩展的最大公约数(Extended GCD)

扩展的gcd算法即除了计算gcd(m,n)还要计算整数x和y,使之满足gcd(m,n) = m.x + n.y。 下面的算法中使用迭代方式。 extendedGCD2方法是extendedGCD的简化版本,考虑到在初值向量r{-1} = [1 0], r{0} = [0 1]下,满足递推关系:r{i} = r{i-2} - q{i}.r{i-1}。

采用Euclid's算法时,不仅要r(余数)的值,还需要q(商)的值。

本例实现参考了Wikipedia中介绍的迭代方法:http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm

/**
 * 
 * @author ljs 2011-5-17
 * 
 * solve extended gcd using Euclid's Algorithm and Iterative Method
 *
 */
public class ExtGCD_Euclid {	
	/**
	 * caculate x,y to satisfy Bezout Identity: m.x + n.y = gcd(m,n)
	 * @param m
	 * @param n
	 * @return {d,x,y} for: d = m.x + n.y;
	 */
	public static int[] extendedGCD(int m,int n){
		m = (m<0)?-m:m;
		n = (n<0)?-n:n;
		
		if(n == 0 ){
			return new int[]{m,1,0};
		}
		
		int r = m % n;
		int q = m / n;
		if(r ==0)
			return new int[]{n,0,1};
		else{
			m=n;
			n=r;
			r = m % n;
			int lastq = q;
			q = m / n;
			if(r==0){
				return new int[]{n,1,-lastq};
			}else{
				int coeffM1=1;
				int coeffN1=-lastq;
				//r2 = n - q2.r1
				int coeffM2=-q;
				int coeffN2=1+lastq * q;
				
				while(n!=0){
					m=n;
					n=r;
					r = m%n;
					q = m / n;
					if(r==0){
						break;
					}else{			
						//for k-th loop, r{k} = r{k-2} - q{k}.r{k-1}, here q{k} is quotient = m{k} / n{k}			
						int coeffM3=coeffM1 - q*coeffM2;
						int coeffN3=coeffN1 - q*coeffN2;	
						coeffM1 = coeffM2;
						coeffN1 = coeffN2;
						coeffM2 = coeffM3;
						coeffN2 = coeffN3;
					}						
				}
				return new int[]{n,coeffM2,coeffN2};
			}
		}		
	}
	
	/**
	 * simplified from the above extendedGCD(m,n)
	 * @see also "http://en.wikipedia.org/wiki/Extended_Euclidean_algorithm"
	 * @param m
	 * @param n
	 * @return {d,x,y} for: d = m.x + n.y;
	 */
	public static int[] extendedGCD2(int m,int n){
		m = (m<0)?-m:m;
		n = (n<0)?-n:n;
		
		int r00=1,r01=0;  //[1 0]
		int r10=0,r11=1;  //[0 1]
		
		int d = 0;
		int x = r00;
		int y = r01;
		while(n!=0){
			int remainder = m%n;
			int quotient = m/n;
			
			if(remainder == 0){			
				x = r10;
				y = r11;
			}else{
				int tmp0 = r00 - quotient*r10;
				int tmp1 = r01 - quotient*r11;
				r00=r10;
				r01=r11;
				r10 = tmp0;
				r11 = tmp1;
			}			
			
			m = n;
			n = remainder;
		}
		d = m;
		
		return new int[]{d,x,y};
	}
	

	public static void print(int m,int n,int[] extGCDResult){
		m = (m<0)?-m:m;
		n = (n<0)?-n:n;
		System.out.format("extended gcd of %d and %d is: %d = %d.{%d} + %d.{%d}%5s%n",m,n,extGCDResult[0],m,extGCDResult[1],n,extGCDResult[2],(m*extGCDResult[1] + n * extGCDResult[2] == extGCDResult[0])?"OK":"WRONG!!!");		
	}
	
	public static void main(String[] args) {
		
		int m = -18;
		int n= 12;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		//co-prime
		m = 15;
		n= 28;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
				
		m = 6;
		n= 3;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 6;
		n= 3;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 6;
		n= 0;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 0;
		n= 6;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 0;
		n= 0;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 1;
		n= 1;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 3;
		n= 3;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 2;
		n= 2;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 1;
		n= 4;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 4;
		n= 1;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 10;
		n= 14;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 14;
		n= 10;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		m = 10;
		n= 4;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		
		m = 273;
		n= 24;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
		
		
		m = 120;
		n= 23;
		print(m,n,extendedGCD(m,n));
		print(m,n,extendedGCD2(m,n));
			
		
	}
}

转载于:https://www.cnblogs.com/ljsspace/archive/2011/06/05/2073366.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值