在计算机中,通常用int,long来存储整形数字,但由于空间问题,当数字过大时,long也存储不了。因此当需要高精度计算大数的时候,该怎样处理呢?(不利用大数类)
现目前我有三条思路
- 模拟传统的人工乘法
- 竖式优化的乘法
- 分而治之
- 利用BigInteger类
1. 传统的人工乘法
思路:将乘数的每一位与被乘数相乘,得到的结果后面追加适当的0元素,再将所有的结果相加即可
此思路要用到额外的两个方法
- 将两个大数相加
- 一位数乘以多位数(包含一位数的情况)
代码如下:
/** 415. 字符串相加 */
public String addStrings(String num1, String num2) {
int len1 = num1.length(), len2 = num2.length(), temp = 0;
int max = Math.max(len1, len2);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < max; ++ i) {
temp += i < len1 ? num1.charAt(len1 - 1 - i) - '0' : 0;
temp += i < len2 ? num2.charAt(len2 - 1 - i) - '0': 0;
stringBuilder.append(temp % 10);
temp /= 10;
}
if(temp != 0) stringBuilder.append(temp);
return stringBuilder.reverse().toString();
}
/** 43. 字符串相乘 */
public String multiply(String num1, String num2) {
if("0".equals(num1) || "0".equals(num2)) return "0";
int len2 = num2.length();
String string = "";
for (int i = 0; i < len2; ++ i) {
// 追加i个0
StringBuilder stringBuilder = new StringBuilder();
for (int j = 0; j < i; j++) {
stringBuilder.append(0);
}
string = addStrings(string, mul(num2.charAt(len2 - 1 - i), num1) + stringBuilder);
}
return string;
}
/** 一位数乘以多位数 */
public String mul(char ch, String string) {
int len = string.length();
int num = ch - 48, carry = 0;
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < len; i++) {
carry += num * (int)(string.charAt(len - 1 - i) - '0');
stringBuilder.append(carry % 10);
carry /= 10;
}
if(carry != 0) stringBuilder.append(carry);
return stringBuilder.reverse().toString();
}
2. 利用竖式优化
注意两个点:
- 一个长度为n的和一个长度为m的数相乘,其结果的长度最多为n+m(不信你试试)
- num1[i]和num2[j]相乘一定不超过两位数。第一位位于arr[i + j] 第二位位于arr[i + j + 1]
public String multiply(String num1, String num2) {
if("0".equals(num1) || "0".equals(num2)) return "0";
int len1 = num1.length(), len2 = num2.length(), temp;
int[] arr = new int[len1 + len2];
for (int i = len1 - 1; i >= 0; -- i) {
int n1 = num1.charAt(i) - 48;
for (int j = num2.length() - 1; j >= 0; -- j) {
int n2 = num2.charAt(j) - 48;
temp = arr[i + j + 1] + n1 * n2;
arr[i + j + 1] = temp % 10;
arr[i + j] += temp / 10;
}
}
StringBuilder stringBuilder = new StringBuilder();
int i = arr[0] == 0 ? 1 : 0;
while (i < arr.length) {
stringBuilder.append(arr[i ++]);
}
return stringBuilder.toString();
}
3. 分而治之
算法思路:
代码实现:
/** 44. 分治算法 */
public String multiply2(String num1, String num2) {
if(num1.length() == 1 || num2.length() == 1) return String.valueOf(Integer.valueOf(num1) * Integer.valueOf(num2));
// 拆分的长度
int middle = Math.max(num1.length(), num2.length()) / 2;
// 拆分出a b c d
String a = num1.substring(0, num1.length() - middle);
String b = num1.substring(num1.length() - middle);
String c = num2.substring(0, num2.length() - middle);
String d = num2.substring(num2.length() - middle);
// 计算a * c,b * d,和b * c + a * d
String ac = multiply2(a, c);
String bd = multiply2(b, d);
// b * c + a * d = (a + b) * (c + d) - a * c - b * d
String bcad = subStract(subStract(multiply2(addStrings(a, b), addStrings(c, d)), ac), bd);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < 2 * middle; ++ i) {
stringBuilder.append('0');
}
return addStrings(bd, addStrings(ac + stringBuilder.toString(), bcad + stringBuilder.substring(middle)));
}
/** 415. 字符串相加 */
public String addStrings(String num1, String num2) {
int len1 = num1.length(), len2 = num2.length(), temp = 0;
int max = Math.max(len1, len2);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < max; ++ i) {
temp += i < len1 ? num1.charAt(len1 - 1 - i) - '0' : 0;
temp += i < len2 ? num2.charAt(len2 - 1 - i) - '0': 0;
stringBuilder.append(temp % 10);
temp /= 10;
}
if(temp != 0) stringBuilder.append(temp);
return stringBuilder.reverse().toString();
}
/** 字符串的减法 */
public String subStract(String string1, String string2) {
int len1 = string1.length(), len2 = string2.length(), judge;
if(len1 > len2) {
judge = 1;
}else if (len1 < len2) {
judge = -1;
}else {
judge = string1.compareTo(string2);
}
if(judge < 0) return "-" + subStract(string2, string1);
else if (judge == 0) return "0";
int temp = 0;
int max = Math.max(len1, len2);
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < max; i++) {
int a = i < len1 ? string1.charAt(len1 - 1 - i) - '0' : 0;
int b = i < len2 ? string2.charAt(len2 - 1 - i) - '0' : 0;
int num = a - temp - b;
if(num < 0) {
num = 10 + a - b - temp;
temp = 1;
}else {
temp = 0;
}
stringBuilder.append(num);
}
// 去掉多余的0
for (int i = stringBuilder.length() - 1; i >= 0; -- i) {
if(stringBuilder.charAt(i) != '0') {
break;
}
stringBuilder.deleteCharAt(i);
}
return stringBuilder.reverse().toString();
}
4. 用BigInteger类
略