自己动手写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
进制问题
表示一串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;elseresult=-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]);}}
- 自己动手写Java大整数《1》表示与加减
- 自己写Java大整数《一》表示和加减
- 自己动手写Java大整数《5》总结
- 自己动手写Java大整数《2》优化和乘法
- 自己动手写Java大整数《3》除法和十进制转换
- java 字符与整数加减
- 大整数加减 加减运算
- 自己动手写Java大整数《4》扩展欧几里得和Mod逆
- 大整数加减
- 大整数加减
- 大整数加减乘法
- java.BigInteger(java表示大整数)
- 【自己动手写数据结构】 -- 循环队列的表示与实现
- 作业二:大整数加减
- 用补码表示整数及加减运算
- 用补码表示整数及加减运算
- 剑指offer之面试题12-1:大整数加减
- 大整数的加减乘运算
- osx中使用navicat连接sqlserver查看functions中的存储过程的内容时无法显示的问题
- linux 内核 练习 3
- 图的创建BFS DFS
- 主从库同步耗时查询
- UIImageJPEGRepresentation和UIImagePNGRepresentation
- 自己动手写Java大整数《1》表示与加减
- bzoj1968: [Ahoi2005]COMMON 约数研究
- 使用ALAssetsLibrary读取所有照片
- [leetcode] Roman to Integer
- MFC消息响应机制(一)
- ubuntu12.04上安装gcc4.8
- HDU 4862 Jump 最小k路径覆盖 费用流
- ALAsset和ALAssetRepresentation详解
- [NWPU][2014][TRN][5]二分和贪心 HDU 4296