在不使用BigInteger这个类的情况下,如何自己去实现两个超级大的数相加呢?
首先我们来看一下加法的原则: 1.同号相加,把两数相加,结果符号位取任意一个数的符号
2.异号相加,取较大的数减去较小的数,结果符号位取较大的数的符号位
由于是超级大数,我们使用String来存储。首先要判断这两个大数的符号位,以及正确性(不能是0开头的数,也不能含有其它字母和符号)
/**
* 大整数求和
*
* @param num1
* @param num2
* @return
*/
public static String bigNumberSum(String num1, String num2) {
// 最后的符号
char sign = '+';
char sign1 = num1.charAt(0);
char sign2 = num2.charAt(0);
String number1 = "";
String number2 = "";
// 去符号位操作
if (sign1 == '-' || sign1 == '+') {
number1 = num1.substring(1);
} else {
sign1 = '+';
number1 = num1;
}
// 去符号位操作
if (sign2 == '-' || sign2 == '+') {
number2 = num2.substring(1);
} else {
sign2 = '+';
number2 = num2;
}
boolean isDig1 = number1.matches("[1-9][0-9]*");
boolean isDig2 = number2.matches("[1-9][0-9]*");
if (!isDig1 || !isDig2) {
throw new NumberFormatException("输入的数据不是正确的整数");
}
return "";
}
首先要知道的是两个数相加,结果的最大长度是两数最长的长度+1。所以我们用一个int[len]数组来存储各位相加的结果。
int length1 = number1.length();
int length2 = number2.length();
// 两数相加结果最长为求最长的数的长度+1
int len = length1 > length2 ? length1 + 1 : length2 + 1;
int[] result = new int[len];
为了从个位开始,我们需要对字符进行反转
char[] chars1 = new StringBuffer(number1).reverse().toString().toCharArray();
char[] chars2 = new StringBuffer(number2).reverse().toString().toCharArray();
boolean longerIs1 = length1 > length2 ? true : false;
// 同号则直接相加
if (sign1 == sign2) {
sign = sign1;
if (longerIs1) {
for (int i = 0; i < length2; i++) {
result[i] = (chars1[i] - '0') + (chars2[i] - '0');
}
for (int j = length2; j < length1; j++) {
result[j] = (chars1[j] - '0');
}
} else {
for (int i = 0; i < length1; i++) {
result[i] = (chars1[i] - '0') + (chars2[i] - '0');
}
for (int j = length1; j < length2; j++) {
result[j] = (chars2[j] - '0');
}
}
// 处理进位
for (int i = 0; i < len; i++) {
if (result[i] >= 10) {
result[i + 1] += result[i] / 10;
result[i] = result[i] % 10;
}
}
}
接着来讨论一个整数一个负数相加的情况。长度不等,拿长的数减去短的数,便于处理借位的情况。如果长度相等,这拿较大的数减去较小的。比如说2233,2100。通过String的compareTo方法比较,获取哪个数较大。当然啦,这里是相减,所以会出现借位的情况。所有最后要对借位进行处理。
else {// 异号相加,如果length1>length2,拿长的数减去小的数
if (longerIs1) {
sign = sign1;
for (int i = 0; i < length2; i++) {
result[i] = (chars1[i] - '0') - (chars2[i] - '0');
}
for (int j = length2; j < length1; j++) {
result[j] = chars1[j] - '0';
}
} else {
if (length1 == length2) {
// 拿大的数减去小的数
boolean lager = number1.compareTo(number2)>0 ? true : false;
if (lager) {
sign = sign1;
for (int i = 0; i < length1; i++) {
result[i] = (chars1[i] - '0') - (chars2[i] - '0');
}
} else {
sign = sign2;
for (int i = 0; i < length1; i++) {
result[i] = (chars2[i] - '0') - (chars1[i] - '0');
}
}
} else {// length1
// 结果没有进位时的0处理
boolean flag = true;
StringBuffer resultStr = new StringBuffer();
for (int i = result.length - 1; i >= 0; i--) {
if (result[i] == 0 && flag) {
continue;
}
flag = false;
resultStr.append(result[i]);
}
// 符号处理
if (sign == '-') {
return "-" + resultStr.toString();
} else {
return resultStr.toString();
}
/**
* 大整数求和
* @param num1
* @param num2
* @return
*/
public static String bigNumberSum(String num1, String num2) {
// 最后的符号
char sign = '+';
char sign1 = num1.charAt(0);
char sign2 = num2.charAt(0);
String number1 = "";
String number2 = "";
// 去符号位操作
if (sign1 == '-' || sign1 == '+') {
number1 = num1.substring(1);
} else {
sign1 = '+';
number1 = num1;
}
// 去符号位操作
if (sign2 == '-' || sign2 == '+') {
number2 = num2.substring(1);
} else {
sign2 = '+';
number2 = num2;
}
boolean isDig1 = number1.matches("[1-9][0-9]*");
boolean isDig2 = number2.matches("[1-9][0-9]*");
if (!isDig1 || !isDig2) {
throw new NumberFormatException("输入的数据不是正确的格式的整数");
}
char[] chars1 = new StringBuffer(number1).reverse().toString().toCharArray();
char[] chars2 = new StringBuffer(number2).reverse().toString().toCharArray();
int length1 = number1.length();
int length2 = number2.length();
// 两数相加结果最长为求最长的数的长度+1
int len = length1 > length2 ? length1 + 1 : length2 + 1;
int[] result = new int[len];
boolean longerIs1 = length1 > length2 ? true : false;
// 同号则直接相加
if (sign1 == sign2) {
sign = sign1;
if (longerIs1) {
for (int i = 0; i < length2; i++) {
result[i] = (chars1[i] - '0') + (chars2[i] - '0');
}
for (int j = length2; j < length1; j++) {
result[j] = (chars1[j] - '0');
}
} else {
for (int i = 0; i < length1; i++) {
result[i] = (chars1[i] - '0') + (chars2[i] - '0');
}
for (int j = length1; j < length2; j++) {
result[j] = (chars2[j] - '0');
}
}
// 处理进位
for (int i = 0; i < len; i++) {
if (result[i] >= 10) {
result[i + 1] += result[i] / 10;
result[i] = result[i] % 10;
}
}
} else {// 异号相加,如果length1>length2,拿长的数减去小的数
if (longerIs1) {
sign = sign1;
for (int i = 0; i < length2; i++) {
result[i] = (chars1[i] - '0') - (chars2[i] - '0');
}
for (int j = length2; j < length1; j++) {
result[j] = chars1[j] - '0';
}
} else {
if (length1 == length2) {
// 拿大的数减去小的数
boolean lager = number1.compareTo(number2)>0 ? true : false;
if (lager) {
sign = sign1;
for (int i = 0; i < length1; i++) {
result[i] = (chars1[i] - '0') - (chars2[i] - '0');
}
} else {
sign = sign2;
for (int i = 0; i < length1; i++) {
result[i] = (chars2[i] - '0') - (chars1[i] - '0');
}
}
} else {// length1= 0; i--) {
if (result[i] == 0 && flag) {
continue;
}
flag = false;
resultStr.append(result[i]);
}
// 符号处理
if (sign == '-') {
return "-" + resultStr.toString();
} else {
return resultStr.toString();
}
}
在我写完上面的代码时,回头去看瞬间懵比了。那么多的if else,要看好久才能看懂这些逻辑啊。要是面试官看到这些代码,估计机会都不给了。所以打算改进一下逻辑,让整体的代码结构更加清晰易懂。从头分析一遍,我们的思路,我们可以发现同号异号这两种情况是必然要判断的,我们的代码主要用在了什么方面呢。我猜你应该发现了吧,大量的代码用来处理两个数的长度不一致的情况了。我们可以看到当它们的长度相等的时候,只需要执行一个for循环即可。
if (length1 == length2) {
// 拿大的数减去小的数
boolean lager = number1.compareTo(number2)>0 ? true : false;
if (lager) {
sign = sign1;
for (int i = 0; i < length1; i++) {
result[i] = (chars1[i] - '0') - (chars2[i] - '0');
}
} else {
sign = sign2;
for (int i = 0; i < length1; i++) {
result[i] = (chars2[i] - '0') - (chars1[i] - '0');
}
}
}
/**
* 求超大整数的和
* @param num1
* @param num2
* @return
*/
public static String bigNumberSumBetter(String num1, String num2) {
char sign = '+';
char sign1 = num1.charAt(0);
char sign2 = num2.charAt(0);
String number1 = "";
String number2 = "";
// 去符号位操作
if (sign1 == '-' || sign1 == '+') {
number1 = num1.substring(1);
} else {
sign1 = '+';
number1 = num1;
}
// 去符号位操作
if (sign2 == '-' || sign2 == '+') {
number2 = num2.substring(1);
} else {
sign2 = '+';
number2 = num2;
}
boolean isDig1 = number1.matches("[1-9][0-9]*");
boolean isDig2 = number2.matches("[1-9][0-9]*");
if (!isDig1 || !isDig2) {
throw new NumberFormatException("输入的数据不是正确的格式的整数");
}
//两个数的长度
int length1 = number1.length();
int length2 = number2.length();
int len = length1>=length2? length1+1:length2+1;
StringBuffer number1Buffer = new StringBuffer();
StringBuffer number2Buffer = new StringBuffer();
//扩展数据的长度,使它们的长度一样
if(length1>length2){
for(int i=0; i= 10) {
result[i + 1] += result[i] / 10;
result[i] = result[i] % 10;
}
}
}else {
// 拿大的数减去小的数
boolean lager = number1.compareTo(number2)>0 ? true : false;
if (lager) {
sign = sign1;
for (int i = 0; i < len-1; i++) {
result[i] = (chars1[i] - '0') - (chars2[i] - '0');
}
} else {
sign = sign2;
for (int i = 0; i < len-1; i++) {
result[i] = (chars2[i] - '0') - (chars1[i] - '0');
}
}
// 处理借位
for (int i = 0; i < len; i++) {
if (result[i] < 0) {
result[i] += 10;
result[i + 1]--;
}
}
}
// 结果没有进位时的0处理
boolean flag = true;
StringBuffer resultStr = new StringBuffer();
for (int i = result.length - 1; i >= 0; i--) {
if (result[i] == 0 && flag) {
continue;
}
flag = false;
resultStr.append(result[i]);
}
// 符号处理
if (sign == '-') {
return "-" + resultStr.toString();
} else {
return resultStr.toString();
}
}
代码结构更清晰了,也更容易让人读懂。