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

上周粗略计划自己写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类型里。

private int [] digits ;

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

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




符号问题

private int sign;

表示符号。其中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 ;
}


加减法

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

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

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

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; 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;
						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<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)];
			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<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]);
	
	}
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值