java 中针对大整数的运算,提供了 BigInteger 和 BigDecimal ,那么我们 自己如何实现大整数的减法呢?
我们 回忆下 减法的竖式 ,在减法竖式中,我们先减 个位数,再减十位数,如果个位数不够减则像 十位借1,个
位数加上10,计算结果作为个位数结果,十位数字 减一。小数 减大数 = - ( 大数 - 小数):(ps:小数 减大数结果
就是 大数减小数 前面加一个负号)
换成更一般的说法:就是 计算第 i 位相减的时候 需要考虑到 第 i-1 位产生的借位。
类比到 计算机:我们使用char[]数组进行存储 加数和被加数,结果存储到StringBuild
因为我们输入的数是高位在左边,因此我们遍历的时候从最右边遍历,也就是代码中的
pos = len -1, 我们定义一个 变量表示 借位:jieWei,初始值为 0,后续我们计算 第 i 位的差
的时候就可以直接使用如下放方法:
公式:ch1 -'0':从字符 转换成对应的 数字 比如:‘3’-‘0’ = 3
第i位的差 就是:int sub= ch1 - ch2 - jin;
如果 sub < 0 ,则 我们 jieWei= 1, char sumChar = sub +10 +'0' ,
如果 sub >= 0 则 我们 jieWei= 0,
最后一步,千万别忘了,我们还有一个进位!!!
我们把进位 放在最高位。
(ps:StringBuild : 中 insert(i,k),就是在第i的位置插入,当i = 0,也就是说插入到最左边,就是插入到最高位)
我们不考虑 是负数的情况(减数 和被减数 都是正数,如果 有负数时情况会复杂,后续会分析)
/**
* 减法,不考虑负数相减
* @param arr1
* @param arr2
* @return
*/
private static StringBuilder getSubResult(char[] arr1, char[] arr2){
int len1 = arr1.length;
int len2 = arr2.length;
char ch1,ch2;
// 如果被减数的位数 ,少于减数 则结果为负,如果位数相同,逐位比较,直道比较出大小
boolean positive = false;
//
if(len1 > len2){
positive = true;
}
if(len1 == len2){
// 长度一样时候,逐位比较(可以考虑使用string.compareTo)
int temp = 0;
while (temp < len1){
ch1 = arr1[temp];
ch2 = arr2[temp];
if(ch1 != ch2){
positive = (ch1> ch2);
break;
}
temp ++;
}
}
if(positive){
return bigSubSmall(arr1,arr2);
}
// 负数,前面添加负号
return bigSubSmall(arr2,arr1).insert(0,"-");
}
/**
* 大数减小数
* @param bigArr 较大的数
* @param smallArr 较小的数
* @return
*/
private static StringBuilder bigSubSmall(char[] bigArr, char[] smallArr){
int len1 = bigArr.length;
int len2 = smallArr.length;
char[] resultArr = new char[len1];
// 借位
int jieWei = 0;
int pos1 = len1-1,pos2 = len2 -1;
char ch1,ch2;
int resultBit = 0;
int i = len1 -1;
while (pos2>=0){
// 被减数减去 被借去的 值,如果没有借位,jieWei =0,有借位 值 =1
ch1 = (char)( bigArr[pos1--] - jieWei) ;
ch2 = smallArr[pos2--];
resultBit = ch1 - ch2;
// 此处需注意:因为 i 传入函数,在函数中对i-- 出来函数i值是不变的
jieWei = saveResultAndGetJieWei(resultBit,resultArr,i);
i --;
}
while (pos1>=0){
ch1 = bigArr[pos1--];
resultBit = ch1 - jieWei -'0';
jieWei = saveResultAndGetJieWei(resultBit,resultArr,i);
i --;
}
StringBuilder sb = new StringBuilder(len1);
int j=0;
//移除高位的0
for (;j<len1;j++){
if(resultArr[j]!='0'){
break;
}
}
for (;j<len1;j++){
sb.append(resultArr[j]);
}
return sb;
}
private static int saveResultAndGetJieWei(int resultBit,char[] resultArr,int index){
int jieWei = 0;
if(resultBit < 0){
resultBit = resultBit +10 ;
jieWei = 1;
}
// 此处 index 和 index --,出了函数 ,调用者的值是不变的
resultArr[index] = (char) (resultBit+'0');
return jieWei;
}