自己动手写Java大整数《1》表示与加减

来源:互联网 发布:白夜追凶结局知乎 编辑:程序博客网 时间:2024/06/07 02:04

上周粗略计划自己写Java下的大整数运算。

后来仔细想想其实自己动手写大整数运算有1好2不好。2个不好分别是:

1,肯定没有Java内置的BigInteger安全快速;2,自己写的大数包只能自己使用,不具有可移植性。

但是还有一个大大的好处就是

1,促进自己学习和弄清楚大数运算的机制,对自己进步有帮助。

所以我决定开始继续写下去。 


开始在上篇计划中,我大概列出了会遇到的问题。下面我首先解决大数的表示、绝对值的比较大小、取负值和加减法运算。

后面我会不断添加乘法,除法,mod运算等。


我有两个主要的参考资料,

第一就是java内置的BigInteger的代码在“...\java\jdk1.*.*\src.zip”的压缩文件中。

第二就是国外的一个博客http://paul-ebermann.tumblr.com/post/6277562800/big-numbers-self-made-part-0-14-introduction



进制问题

为了避免进制的转换,使用十进制的倍数。
int 类型的数十-2^31-2^31-1 大约是9.33的十进制位。
所以使用int表示一个位,每位是10^9。满足两个小于10^9的数的加法仍然落在int的可表示范围内。
 
long类型的数是-2^63到  2^63-1大约是18.965十进制  
两个两个小于10^9的数相乘正好落到long类型里。

privateint[]digits;

表示一串10^9进制的数,并且这里的选择数组的低位表示10^9进制数的高位。也就是如图所示的

最高位是digits[0],最低位是digits[digits.length].




符号问题

privateintsign;

表示符号。其中sign=-1表示负数;sign=0表示0; sign=1表示正数。


初始化

public DecimalBig(int sign, int[] digits)
{
for(int i=0; i<digits.length; i++){
if (digits[i]<0 || digits[i]>Radix)
throw new IllegalArgumentException("digit " + digits[i] +
" out of range!");
}
this.sign = sign;
this.digits = digits;
}
使用符号和一个数组进行初始化。


取负值

改变sign的值为-sign

public DecimalBig negate()
{
return new DecimalBig(-this.sign, this.digits);
}

绝对大小比较

因为对于不同号加法或者同号减法,都要有一个较大数减去较小数的过程,所以先要比较大小

我这里是很直接的判断。应该有优化代码的方法。

输出-1表示this小于输入;0表示相等;1表示this大于输入。

public int AbsCompare(DecimalBig that)
{
int result =0;
if (this.digits.length>that.digits.length)
result=1;
else{
if (this.digits.length<that.digits.length)
result=-1;
else{
if(this.digits.length==0)
result=0;
else{
int i=0;
while(i<this.digits.length&&this.digits[i]==that.digits[i])
i++;
if(i==this.digits.length)
result=0;
else{
if (this.digits[i]>that.digits[i])
result=1;
else
result=-1;
}
}
}
}
return result;
}


加减法

我们先考虑加法。加法同号的问题比较好解决;直接和十进制加法的规则一样,相应的两个数组相加,这里要注意的是进位的问题;

但是加法不同号的相当于两个数组相应位置相减,这里要注意的是借位和去零的问题。

所以要首先实现两个数组加法,和数组减法(大的减小的)的算法

publicstaticint[]Add(int[]a,int[]b);


publicstaticint[]Substract(int[]Big,int[]little);


然后大数加法(a+b)中再根据两个大数的符号决定里边数组是相加还是相减;

大数减法(a-b)中相当于(a+(-b))。

具体下面代码


/** *  *//** * @author Xue * at 2014.7.20 */public class DecimalBig {/* * 采用10^9进制的计算 */final static int Radix = 1000000000;/* * 美俄基数十进制的长度 */final static int Radix_Dicimal_length=9;/* * 每一个大整数都表示成一串int类型的数 */private int[] digits;/* * 符号,其中-1代表负数,0代表0,1代表正数 */private int sign;/* * 构造函数,这里选择的是小头高位,大头低位的方法存储的数据 */public DecimalBig(int sign, int[] digits){for(int i=0; i<digits.length; i++){if (digits[i]<0 || digits[i]>Radix)throw new IllegalArgumentException("digit " + digits[i] +                        " out of range!");}this.sign = sign;this.digits = digits;}private static int[] ONE={1};public static final DecimalBig Zero=new DecimalBig(0, new int[0]); public static final DecimalBig One=new DecimalBig(1, ONE);/* * 绝对值大小的比较,this 大则返回1,小返回1,相等返回0 */public int AbsCompare(DecimalBig that){int result =0;if (this.digits.length>that.digits.length)result=1;else{if (this.digits.length<that.digits.length)result=-1;else{if(this.digits.length==0)result=0;else{int i=0;while(i<this.digits.length&&this.digits[i]==that.digits[i])i++;if(i==this.digits.length)result=0;else{if (this.digits[i]>that.digits[i])result=1;elseresult=-1;}}}}return result;}/* * 反转符号, */public DecimalBig negate(){return new DecimalBig(-this.sign, this.digits);}/* * 返回绝对值; */public DecimalBig abs(){return this.sign>=0?this:this.negate();}/* * 加法, */public DecimalBig Add(DecimalBig that){//this 是 0if (this.sign==0)return that;//that 是0if (that.sign==0)return this;//相同符号if (that.sign==this.sign)return new DecimalBig(this.sign, Add(this.digits,that.digits));//不同符号if (this.AbsCompare(that)==0)return Zero;if (this.AbsCompare(that)==1)return new DecimalBig(this.sign, Substract(this.digits,that.digits));return new DecimalBig(that.sign, Substract(that.digits,this.digits));}/* * 减法 */public DecimalBig substract(DecimalBig that){//this 是 0if (this.sign==0)return that.negate();//that 是0if (that.sign==0)return this;//不同符号if (that.sign!=this.sign)return new DecimalBig(this.sign, Add(this.digits,that.digits));//相同符号if (this.AbsCompare(that)==0)return Zero;if (this.AbsCompare(that)==1)return new DecimalBig(this.sign, Substract(this.digits,that.digits));return new DecimalBig(that.sign, Substract(that.digits,this.digits));}/* * 两个数组的加法    */public static int[] Add(int[] x, int[] val){int[] MaxBig, MinBig;/* * 拷贝较长的数到MaxBig较短的数到MinBig */if (x.length<val.length){MaxBig=x;MinBig=val;}else{MaxBig=val;MinBig=x;}/* * 建立要返回的数组addresult;进位制记为carry */int[] addresult = new int[MaxBig.length];int carry=0;/* * 简单的进位加法 */for (int i=MaxBig.length-1;i>=0;i--){int extadd=0;if (i>MaxBig.length-MinBig.length-1)extadd=MinBig[i-(MaxBig.length-MinBig.length)];elseextadd=0;int DigitSum=MaxBig[i]+extadd+carry;addresult[i]=DigitSum%Radix;carry=DigitSum/Radix;}/* * 最高位哟啊是有进位的话,拉长一位 */if (carry==1){ int[] temp = new int[MaxBig.length + 1]; System.arraycopy(addresult, 0, temp, 1, MaxBig.length); temp[0] = carry; addresult = temp;}return addresult;}/* * 两个数组的减法;    */public static int[] Substract(int[] Big, int[] little){/* * 建立要返回的数组addresult;进位制记为carry */int[] subresult = new int[Big.length];int carry=0;/* * 简单的进位加法 */for (int i=Big.length-1;i>=0;i--){int extsub=0;if (i>Big.length-little.length-1)extsub=little[i-(Big.length-little.length)];elseextsub=0;int Digitsub=Big[i]-extsub-carry;if(Digitsub<0){subresult[i]=Digitsub+Radix;carry=1;} else{subresult[i]=Digitsub;carry=0;}}/* * 去掉高位的零 */int i=0;while(i<subresult.length&&subresult[i]==0)i++;    //截取非零项int[] temp = new int[subresult.length-i];System.arraycopy(subresult, i, temp, 0, subresult.length-i);subresult = temp;return subresult;}public static void main(String arg[]){int[] a={573450000, 5, 2, 573450000};int[] b={573450000, 5, 2, 5};DecimalBig c = new DecimalBig(-1,a);DecimalBig d = new DecimalBig(1,b);System.out.println(Add(c.digits, d.digits)[4]);System.out.println(c.AbsCompare(d));System.out.println(c.Add(d).sign);System.out.println(c.Add(d).digits.length);System.out.println(c.Add(d).digits[0]);System.out.println(c.Add(d).digits[1]);System.out.println(c.Add(d).digits[2]);System.out.println(c.Add(d).digits[3]);System.out.println(c.Add(d).digits[4]);}}



0 0
原创粉丝点击