上周粗略计划自己写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
进制问题
表示一串10^9进制的数,并且这里的选择数组的低位表示10^9进制数的高位。也就是如图所示的
最高位是digits[0],最低位是digits[digits.length].
符号问题
private int sign;
表示符号。其中sign=-1表示负数;sign=0表示0; sign=1表示正数。
初始化
取负值
改变sign的值为-sign
绝对大小比较
因为对于不同号加法或者同号减法,都要有一个较大数减去较小数的过程,所以先要比较大小
我这里是很直接的判断。应该有优化代码的方法。
输出-1表示this小于输入;0表示相等;1表示this大于输入。
加减法
我们先考虑加法。加法同号的问题比较好解决;直接和十进制加法的规则一样,相应的两个数组相加,这里要注意的是进位的问题;
但是加法不同号的相当于两个数组相应位置相减,这里要注意的是借位和去零的问题。
所以要首先实现两个数组加法,和数组减法(大的减小的)的算法
public static int[] Add(int[] a, int[] b);
public static int[] 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; iRadix)
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.lengththat.digits[i])
result=1;
else
result=-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 是 0
if (this.sign==0)
return that;
//that 是0
if (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 是 0
if (this.sign==0)
return that.negate();
//that 是0
if (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=0;i--)
{
int extadd=0;
if (i>MaxBig.length-MinBig.length-1)
extadd=MinBig[i-(MaxBig.length-MinBig.length)];
else
extadd=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)];
else
extsub=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