java 进行超大整数的加减乘除四则运算(自己部分实现BigInteger)
问题分析:
加减运算:
两数进行加减,都可以转为两个基本运算:
- 两个非负数相加--------------- plusAdd()
1 private StringBuffer plusAdd(String strNum1,String strNum2){ 2 //把两个数字字符串倒置,并存入字符数组 3 char [] num1 = new StringBuffer(strNum1).reverse().toString().toCharArray(); 4 char [] num2 = new StringBuffer(strNum2).reverse().toString().toCharArray(); 5 int maxLength = Math.max(num1.length,num2.length); 6 int minLength = Math.min(num1.length,num2.length); 7 //n位和m位的非负整数相加的和,要么是max(n,m)位,要么是max(n,m)+1位。 8 StringBuffer value = new StringBuffer(); 9 10 /*--------------计算和数开始------------------------*/ 11 int i,jinWei=0; 12 for(i=0;i<minLength;i++){ 13 int temp = jinWei + num1[i] - '0' +num2[i] - '0'; 14 value.append((char)(temp%10 + '0')); 15 jinWei = temp/10; 16 } 17 if(maxLength == num1.length) 18 jinWei = oneBitAdd(jinWei,num1,i,maxLength,value); 19 else 20 jinWei = oneBitAdd(jinWei,num2,i,maxLength,value); 21 if(jinWei != 0) 22 value.append((char)(jinWei +'0')); 23 /*--------------计算和数结束------------------------*/ 24 return deleteZero(value).reverse(); 25 }
- 一个较大的非负数减去一个不大于前一个数的非负数 ----- plusMinus()
1 private StringBuffer plusMinus(String bigNumStr,String smallNumStr){ 2 //把两个数字字符串倒置,并存入字符数组 3 char [] num1 = new StringBuffer(bigNumStr).reverse().toString().toCharArray(); 4 char [] num2 = new StringBuffer(smallNumStr).reverse().toString().toCharArray(); 5 StringBuffer value = new StringBuffer(); 6 7 /*--------------计算减法开始------------------------*/ 8 int i,temp,jieWei = 0; 9 for(i = 0;i<smallNumStr.length();i++){ 10 temp = num1[i] - jieWei - num2[i]; 11 jieWei = oneBitMinus(temp,value,i); 12 } 13 //处理较大数比较小数多出来的位 14 for(;i<bigNumStr.length();i++){ 15 temp = num1[i] - '0' - jieWei; 16 jieWei = oneBitMinus(temp,value,i); 17 } 18 /*--------------计算减法结束------------------------*/ 19 return deleteZero(value).reverse(); 20 }
假设num1 , num2 分别为被加数 、加数,则最终结果只可能是以下情况:
- num1 非负数 num2 非负数
- num1 负数 num2 负数 、
- num1 非负数 num2 负数
- num1 负数 num2 非负数
上面四种情况可以转为:
- plusAdd(num1,num2)
- - plusAdd(- num1,- num2)
- plusMinus(num1,- num2)
- plusMinus(num2,- num2)
减法类似。
乘法运算:
乘法也可以转化为一个基本运算: 两个正整数相乘----plusMulti()
private StringBuffer plusMulti(StringBuffer str1,StringBuffer str2) { //新建两个StringBuffer,存储两数的前后倒置。 StringBuffer num1 = new StringBuffer(str1.substring(0)).reverse(); StringBuffer num2 = new StringBuffer(str2.substring(0)).reverse(); StringBuffer array = new StringBuffer(); //n位数和m位数相乘,得到的结果的位数只能是n+m或者n+m-1。 int len = str1.length() + str2.length(); for(int i = 0;i<len-1;i++){ array.append('0'); } //标志n+m位 array.append('+'); //模拟竖式计算 for(int i = 0,j,jinWei = 0 ; i < str2.length() ; i++){ jinWei = 0; //进位归位 for(j = 0 ; j < str1.length() ; j++){ int temp = (num2.charAt(i)-'0')*(num1.charAt(j)-'0') + jinWei + array.charAt(i+j) - '0'; array.setCharAt(i+j,(char)(temp%10 + '0')); jinWei = temp /10; } if(jinWei !=0) array.setCharAt(i+j, (char)(jinWei +'0')); } if(array.charAt(len -1) == '+') array.setLength(len-1); return array.reverse(); }
各种情况只和plusMulti()有正负号的区别。其中一个数为0时,直接返回0即可。
除法运算:
模拟手算除法的过程。
除法也可以转化为一个基本运算,两个非负数相除,除数不为0。-------------plusDivide()
1 private StringBuffer plusDivide(String str1,String str2){ //str1 / str2 2 StringBuffer division = new StringBuffer(); 3 StringBuffer remain = new StringBuffer(); 4 5 int end = 0; 6 boolean flag = false; //标志在不够除时,是否需要上0。 7 while(end < str1.length()){ 8 remain.append(str1.charAt(end)); //从被除数那里取一位 9 if(Str1ThanStr2(remain.toString(),str2)){//能整除 10 flag = true; 11 int fullNum = Greatst(remain,str2); 12 StringBuffer fullNumStr2 = plusMulti(new StringBuffer(str2),new StringBuffer(""+fullNum)); 13 division.append(""+fullNum); 14 remain = plusMinus(remain.toString(),fullNumStr2.toString()); 15 } 16 else if(flag)//不够除,补0 17 division.append("0"); 18 if(remain.toString().equals("0")) 19 remain.setLength(0); 20 end++; 21 } 22 if(division.length() == 0){ 23 return division.append('0'); 24 } 25 return division; 26 }
各种情况至于plusDivide()只有符号的区别,除数为0时,特别处理下即可。
代码简介:
对外开放了四个方法:加减乘除。
- public MyBigInteger Minus(MyBigInteger t) 减法
- public MyBigInteger Multi(MyBigInteger t) 乘法
- public MyBigInteger Add(MyBigInteger str) 加法
- public MyBigInteger Divide(MyBigInteger t) 除法
测试:
乘法:进行10000!的运算,与用BigInteger类得到的结果一样。四种情况都测试了,结果一致。至少一个数为0时,也得到了了0。值得信赖!
其他的三种,测试没有乘法详细,如果有bug欢迎指出。
下面的main函数中,提供了
(175 + 231 - 143)*(-1978654)/(-54)
完整代码如下:
1 2 public class MyBigInteger { 3 private StringBuffer data; 4 5 6 public MyBigInteger(){ 7 data = new StringBuffer("0"); 8 } 9 public MyBigInteger(String str){ 10 data = new StringBuffer(str); 11 } 12 public MyBigInteger(StringBuffer str){ 13 data = new StringBuffer(str); 14 } 15 16 public int length(){ 17 return data.length(); 18 } 19 public String toString(){ 20 return data.toString(); 21 } 22 23 public boolean equals(Object obj){ 24 return data == ((MyBigInteger)obj).data; 25 } 26 27 /** 28 * 功能:进行两个非负整数的相加 29 */ 30 private StringBuffer plusAdd(String strNum1,String strNum2){ 31 //把两个数字字符串倒置,并存入字符数组 32 char [] num1 = new StringBuffer(strNum1).reverse().toString().toCharArray(); 33 char [] num2 = new StringBuffer(strNum2).reverse().toString().toCharArray(); 34 int maxLength = Math.max(num1.length,num2.length); 35 int minLength = Math.min(num1.length,num2.length); 36 //n位和m位的非负整数相加的和,要么是max(n,m)位,要么是max(n,m)+1位。 37 StringBuffer value = new StringBuffer(); 38 39 /*--------------计算和数开始------------------------*/ 40 int i,jinWei=0; 41 for(i=0;i<minLength;i++){ 42 int temp = jinWei + num1[i] - '0' +num2[i] - '0'; 43 value.append((char)(temp%10 + '0')); 44 jinWei = temp/10; 45 } 46 if(maxLength == num1.length) 47 jinWei = oneBitAdd(jinWei,num1,i,maxLength,value); 48 else 49 jinWei = oneBitAdd(jinWei,num2,i,maxLength,value); 50 if(jinWei != 0) 51 value.append((char)(jinWei +'0')); 52 /*--------------计算和数结束------------------------*/ 53 return deleteZero(value).reverse(); 54 } 55 /** 56 * 进位加上字符数组一部分 57 * @return 58 */ 59 private int oneBitAdd(int jinWei,char []array,int beginIndex,int endIndex,StringBuffer value){ 60 int temp; 61 for(int i = beginIndex;i<endIndex;i++){ 62 temp = jinWei + array[i] - '0'; 63 jinWei = temp/10; 64 value.append((char)(temp%10+'0')); 65 } 66 return jinWei; 67 } 68 69 /** 70 * 功能:较大的非负整数bigNumStr减去较小的非负整数smallNumStr 71 */ 72 private StringBuffer plusMinus(String bigNumStr,String smallNumStr){ 73 //把两个数字字符串倒置,并存入字符数组 74 char [] num1 = new StringBuffer(bigNumStr).reverse().toString().toCharArray(); 75 char [] num2 = new StringBuffer(smallNumStr).reverse().toString().toCharArray(); 76 StringBuffer value = new StringBuffer(); 77 78 /*--------------计算减法开始------------------------*/ 79 int i,temp,jieWei = 0; 80 for(i = 0;i<smallNumStr.length();i++){ 81 temp = num1[i] - jieWei - num2[i]; 82 jieWei = oneBitMinus(temp,value,i); 83 } 84 //处理较大数比较小数多出来的位 85 for(;i<bigNumStr.length();i++){ 86 temp = num1[i] - '0' - jieWei; 87 jieWei = oneBitMinus(temp,value,i); 88 } 89 /*--------------计算减法结束------------------------*/ 90 return deleteZero(value).reverse(); 91 } 92 /** 93 * 删去多余的0 94 */ 95 private StringBuffer deleteZero(StringBuffer str){ 96 int num=0; 97 for(int i = str.length()-1;i>=0;i--){ 98 if(str.charAt(i) == '0') 99 num++; 100 else 101 break; 102 } 103 if(num != str.length()) 104 str.setLength(str.length()-num); 105 else 106 str = new StringBuffer("0"); 107 return str; 108 } 109 /** 110 * 一位减法 111 */ 112 private int oneBitMinus(int flag,StringBuffer value,int num){ 113 int jieWei; 114 if(flag <0){ 115 value.append((char)(10 +flag + '0')); 116 jieWei = 1; 117 } 118 else{ 119 jieWei = 0; 120 value.append((char)(flag + '0')); 121 } 122 return jieWei; 123 } 124 125 /** 126 * 名称:内部调用的减法。 127 * 功能:两个非负数相减。 128 * 结果:返回运算结果的前后倒置。 129 */ 130 private StringBuffer innerMinus(String str1,String str2){ 131 StringBuffer temp; 132 if(Str1ThanStr2(str1,str2))//若str1更大 133 temp = plusMinus(str1,str2); 134 else{ 135 temp = plusMinus(str2,str1); 136 if(!temp.toString().equals("0")) 137 temp.reverse().append('-').reverse(); 138 } 139 return temp; 140 } 141 /** 142 * 判断正负 143 * true -- 非负 false -- 负 144 */ 145 public boolean isNoNegative(MyBigInteger t){ 146 if(t.data.charAt(0) == '-') 147 return false; 148 return true; 149 } 150 151 /** 152 * 对外开放的加法接口 153 * 计算str1 + str2 154 */ 155 public MyBigInteger Add(MyBigInteger str){ 156 //两数都非负 157 if(isNoNegative(this) && isNoNegative(str)) 158 data = plusAdd(data.toString(),str.data.toString()); 159 else if(!isNoNegative(this) && !isNoNegative(str)){ 160 StringBuffer temp = plusAdd(data.substring(1),str.data.substring(1)); 161 if(!temp.toString().equals("0")) 162 data = temp.reverse().append('-').reverse(); 163 else 164 data = temp; 165 } 166 else if(!isNoNegative(this) && isNoNegative(str)) 167 data = innerMinus(str.data.toString(),data.substring(1)); 168 else 169 data = innerMinus(data.toString(),str.data.substring(1)); 170 return this; 171 } 172 /** 173 * 对外开放的减法。 174 * 计算str1 - str2 175 */ 176 public MyBigInteger Minus(MyBigInteger t){ 177 //两数都为正。 178 if(isNoNegative(this) && isNoNegative(t)) 179 data = innerMinus(this.data.toString(),t.data.toString()); 180 //两数都为负时,需要对innerMinus得到的结果逆转正负。 181 else if(!isNoNegative(this) && !isNoNegative(t)) 182 data = innerMinus(t.data.substring(1),data.substring(1)); 183 //this 为负,t为非负。 184 else if(!isNoNegative(this) && isNoNegative(t)){ 185 StringBuffer temp = plusAdd(data.substring(1),t.data.toString()); 186 if(!temp.toString().equals("0")) 187 data = temp.reverse().append('-').reverse(); 188 else 189 data = temp; 190 } 191 //this 为非负,str为负。 192 else 193 data = plusAdd(data.toString(),t.data.substring(1).toString()); 194 return this; 195 } 196 197 /** 198 * 内部使用的两个正整数乘法 199 */ 200 private StringBuffer plusMulti(StringBuffer str1,StringBuffer str2) { 201 //新建两个StringBuffer,存储两数的前后倒置。 202 StringBuffer num1 = new StringBuffer(str1.substring(0)).reverse(); 203 StringBuffer num2 = new StringBuffer(str2.substring(0)).reverse(); 204 StringBuffer array = new StringBuffer(); 205 //n位数和m位数相乘,得到的结果的位数只能是n+m或者n+m-1。 206 int len = str1.length() + str2.length(); 207 for(int i = 0;i<len-1;i++){ 208 array.append('0'); 209 } 210 //标志n+m位 211 array.append('+'); 212 213 //模拟竖式计算 214 for(int i = 0,j,jinWei = 0 ; i < str2.length() ; i++){ 215 jinWei = 0; //进位归位 216 for(j = 0 ; j < str1.length() ; j++){ 217 int temp = (num2.charAt(i)-'0')*(num1.charAt(j)-'0') + jinWei + array.charAt(i+j) - '0'; 218 array.setCharAt(i+j,(char)(temp%10 + '0')); 219 jinWei = temp /10; 220 } 221 if(jinWei !=0) 222 array.setCharAt(i+j, (char)(jinWei +'0')); 223 } 224 if(array.charAt(len -1) == '+') 225 array.setLength(len-1); 226 return array.reverse(); 227 } 228 /** 229 * 对外开放的乘法 230 */ 231 public MyBigInteger Multi(MyBigInteger t){ 232 //两数至少有一个为0 233 if(data.toString().equals("0") || t.data.toString().equals("0")) 234 data = new StringBuffer("0"); 235 else{ 236 //两数都是正数 237 if(isNoNegative(this) && isNoNegative(t)) 238 data = plusMulti(data,t.data).reverse(); 239 //两数都是负数 240 else if(!isNoNegative(this) && !isNoNegative(t)) 241 data = plusMulti(new StringBuffer(data.substring(1)),new StringBuffer(t.data.substring(1))); 242 243 //两数一正一负 244 else if(isNoNegative(this) && !isNoNegative(t)) 245 data = plusMulti(data,new StringBuffer(t.data.substring(1))).reverse().append('-').reverse(); 246 else 247 data = plusMulti(new StringBuffer(data.substring(1)),t.data).reverse().append('-').reverse(); 248 } 249 return this; 250 } 251 /** 252 * 两个非负数相除,除数不为0 253 * 返回:没有前后倒置的正确的结果 254 */ 255 private StringBuffer plusDivide(String str1,String str2){ 256 StringBuffer division = new StringBuffer(); 257 StringBuffer remain = new StringBuffer(); 258 259 int end = 0; 260 boolean flag = false; 261 while(end < str1.length()){ 262 remain.append(str1.charAt(end)); 263 if(Str1ThanStr2(remain.toString(),str2)){//能整除 264 flag = true; 265 int fullNum = Greatst(remain,str2); 266 StringBuffer fullNumStr2 = plusMulti(new StringBuffer(str2),new StringBuffer(""+fullNum)); 267 division.append(""+fullNum); 268 remain = plusMinus(remain.toString(),fullNumStr2.toString()); 269 } 270 else if(flag)//不够除,补0 271 division.append("0"); 272 if(remain.toString().equals("0")) 273 remain.setLength(0); 274 end++; 275 } 276 if(division.length() == 0){ 277 return division.append('0'); 278 } 279 return division; 280 } 281 /** 282 * 对外开放的减法 283 */ 284 public MyBigInteger Divide(MyBigInteger t){ 285 if(t.data.toString().equals("0")) 286 System.out.println("除零异常"); 287 else{ 288 if(isNoNegative(this) && isNoNegative(t)) 289 data = plusDivide(data.toString(),t.data.toString()); 290 else if(!isNoNegative(this) && !isNoNegative(t)){ 291 data = plusDivide(data.substring(1),t.data.substring(1)); 292 } 293 else{ 294 StringBuffer temp; 295 if(!isNoNegative(this) && isNoNegative(t)) 296 temp = plusDivide(data.substring(1),t.data.toString()); 297 else 298 temp = plusDivide(data.toString(),t.data.substring(1)); 299 if(temp.toString().equals("0")) 300 data = temp; 301 else 302 data = temp.reverse().append('-').reverse(); 303 } 304 } 305 return this; 306 } 307 308 /* 309 * 找出最大 310 */ 311 private int Greatst(StringBuffer str1,String str2){ 312 for(int i = 1;i<10;i++){ 313 StringBuffer num2 = new StringBuffer(str2); 314 for(int j =0;j<i;j++){//(i +1)倍 315 num2 = plusAdd(num2.toString(),str2); 316 } 317 if(!Str1ThanStr2(str1.toString(),num2.toString())){ 318 return i; 319 } 320 } 321 return -1; 322 } 323 /** 324 * 判断str1、str2的大小 325 * 返回:str1>= str2 -----true 326 * str1< str2 -----false 327 */ 328 private static boolean Str1ThanStr2(String str1,String str2){ 329 boolean flag;//1 代表str1大些;2代表str2大些 330 //判断两个非负数,谁大。 331 if(str1.length() == str2.length()){ 332 if(str1.compareTo(str2)<0) 333 flag = false; 334 else 335 flag =true; 336 } 337 else{ 338 if(str1.length() >str2.length()) 339 flag = true; 340 else 341 flag = false; 342 } 343 return flag; 344 } 345 346 347 public static void main(String[] args) { 348 MyBigInteger a1 = new MyBigInteger("175"); 349 MyBigInteger a2 = new MyBigInteger("231"); 350 MyBigInteger a3 = new MyBigInteger("143"); 351 MyBigInteger a4 = new MyBigInteger("-1978654"); 352 MyBigInteger b = new MyBigInteger("-54"); 353 MyBigInteger b1 = new MyBigInteger("0"); 354 //175 + 231 - 143 355 System.out.println(a1.Add(a2).Minus(a3)); 356 //(175 + 231 - 143)*(-1978654) 357 System.out.println(a1.Multi(a4)); 358 //(175 + 231 - 143)*(-1978654)/(-54) 359 System.out.println(a1.Divide(b)); 360 //0 361 System.out.println(a1.Multi(b1)); 362 } 363 }