/*
*我把这个大整数的系列写成了Code中的项目,见https://code.csdn.net/XUE_HAIyang/bignumber
*/
之前已经完成了大整数的表示、绝对值的比较大小、取负值、加减法运算、乘法运算以及除法和余数运算。具体见我的主页前三篇博客(自己动手写Java系列
)。
这篇博客添加求大整数GCD、扩展欧几里得算法和求Mod逆的算法。
扩展欧几里得算法
说道扩展的欧几里得算法,首先我们看下简单的欧几里得算法。经典的欧几里得算法就是
计算两个整数的最大公因子的算法,所基于的原理就是GCD(a, b)=GCD(b, a%b). 不断地迭代
下去就行了。代码见
/* * mod 运算,模数是一个正数,被模数可以是负数,返回mod数 */ public DecimalBig Mod(DecimalBig modnumber) { DecimalBig tempthis =Zero; if (this.sign==-1) tempthis=this.DivideReminder(modnumber).Add(modnumber); else tempthis=this; return tempthis.DivideReminder(modnumber); } /** * Returns a DecimalBig whose value is the greatest common divisor of * {@code abs(this)} and {@code abs(val)}. Returns 0 if * {@code this == 0 && val == 0}. * * @param val value with which the GCD is to be computed. * @return {@code GCD(abs(this), abs(val))} */ public DecimalBig gcd(DecimalBig val) { if(val==Zero) return this; return val.gcd(this.Mod(val)); }
扩展的欧几里得算法不仅要计算a和b的做大公因子而且还要将其用a和b线性表出,
也就是计算出x和y使得GCD(a, b)=xa+yb;
算法我就引用<introduction to modern Computer Algebra>上的算描述了。
实现见代码
/** * Returns a DecimalBig whose value is the linear representation of * {@code abs(this)} modulus {@code abs(val)}. * * 这里边我们返回的是x使得x*this+yval=GCD(this,val); * 如果return为t0则返回的是y使得x*this+yval=GCD(this,val)。 */ private DecimalBig ExtGCD(DecimalBig val) { DecimalBig r0=this, r1=val; DecimalBig s0=One, s1=Zero; DecimalBig t0=Zero, t1=One; DecimalBig temp_r, temp_s, temp_t; while(r1.Compare(Zero)!=0) { DecimalBig q=r0.Divide(r1); <span style="white-space:pre"> </span>temp_r=r0.Substract(q.Multiply(r1)); <span style="white-space:pre"> </span>temp_s=s0.Substract(q.Multiply(s1)); <span style="white-space:pre"> </span>temp_t=t0.Substract(q.Multiply(t1)); <span style="white-space:pre"> </span> r0=r1;r1=temp_r; s0=s1;r1=temp_s; t0=t1;r1=temp_t; } return s0; }
求Mod逆的算法。
扩展的欧几里得算法已经实现了,求mod 逆就是公因子是1的特例
/** * Returns a DecimalBig whose value is the greatest common divisor of * {@code abs(this)} and {@code abs(val)}. Returns 0 if * {@code this == 0 && val == 0}. * * @param val value with which the GCD is to be computed. * @return {@code GCD(abs(this), abs(val))} */ public DecimalBig Inv_Mod(DecimalBig val) { if (val.sign != 1) throw new ArithmeticException("DecimalBig: modulus not positive"); if (this.gcd(val).Compare(One)==1) throw new ArithmeticException("DecimalBig: modulus and this have commen dividor >1 "); return this.ExtGCD(val); }