java - 大数乘法算法并不总是有效
问题描述
我正在尝试创建一个函数,该函数从输入文件中读取两个正自然数,并在计算后将其乘积写入输出文件。
这些数字是“大数字”,它们不能存储在变量中,例如int
我long
想将它们的数字存储在数组中。
我编写了以下代码,该代码似乎适用于某些数字,但例如在插入时失败
55545252575453525348514954525256515056485755545157575748525349575251565256515554545052494854495550525752505756 * 50485456554954525356575657575048555450535257534951545354504957495454525448485751565254525155515656575655535754
那应该是
2804227435732034912849259183651914853320425721942955023578511952364152651715628400479161029284275992691222252865738869930419556645027062168262691246978645407150215825953157986304093759319409280056139599351010978148800024
我明白了
2804227435732034912838248072540803742208304509820742801356289729131829419382295067135726685849922558246677798320394335486985213210683628834929357923746322174827983613731945865091982648208298268945129498351010978148800024
这是代码:
public static void multiplication(String inFileName, String outFileName) {
int[] a, b, res; //a is the first number, b is the second number, res is the final result
int a_i, b_i; //indexes to navigate inside the numbers
a = readBigNumber(inFileName, 0); //This works
if(a == null) return;
System.out.print("*** a: "); printIntArray(a); System.out.println(""); //DEBUG
b = readBigNumber(inFileName, 1); //This works
if(b == null) return;
System.out.print("*** b: "); printIntArray(b); System.out.println(""); //DEBUG
res = new int[a.length + b.length + 1]; //The result cannot be longer than this
Arrays.fill(res, 0); //Fill the array with zeros
//if the length of a < length of b, swap
int[] tempArr;
if (a.length < b.length) {
tempArr = new int[a.length];
System.arraycopy(a, 0, tempArr, 0, a.length);
a = new int[b.length];
System.arraycopy(b, 0, a, 0, b.length);
b = new int[tempArr.length];
System.arraycopy(tempArr, 0, b, 0, tempArr.length);
}
//this algorithm works like the "manual" column multiplication
int temp;
int res_i = 0; //index to navigate in the res array
int carry = 0;
for(b_i = b.length-1; b_i >= 0; b_i--) {
for(a_i = a.length-1; a_i >= 0; a_i--) {
temp = a[a_i] * b[b_i] + carry; //save the product in a temp variable
res_i = res.length - 1 - (a.length - 1 - a_i) - (b.length - 1 - b_i); //calculate the index in the res array
//I need to have just one digit [0-9]
if(temp > 9) { //If temp has more than one digit, take the right-one and put the left-one in the carry
res[res_i] += temp % 10; //right-digit
carry = (temp / 10) % 10; //left-digit
} else {
res[res_i] += temp;
carry = 0;
}
}
//when I exit the a-loop, if the carry is not 0, I have to put it in the result before continuing
if(carry > 0) {
res[res_i - 1] += carry;
carry = 0;
}
}
//Once completed, each array cell could have more than one digit.
//Check it right to left and if so, keep the right-digit e sum the left-digit in the left cell
for(int i = res.length-1; i >= 0; i--) {
if(res[i] > 9) {
res[i - 1] += (res[i] / 10) % 10; //left-digit
res[i] = res[i] % 10; //right-digit
}
}
//Write the final result
String res_str = "";
int start_i = 0;
while(start_i < res.length && res[start_i] == 0) start_i++; //Ignore initial zeros
if(start_i == res.length) {
writeBigNumber(outFileName, "0"); //I checked the whole array, the product is 0
} else {
for(int i = start_i; i < res.length; i++) {
res_str += String.valueOf(res[i]);
}
writeBigNumber(outFileName, res_str);
}
System.out.println("*** res: " + res_str); //DEBUG
}
这些是一些“辅助功能”:
//This works
private static int[] readBigNumber(String inFileName, int lineIndex) {
File inputFile = new File(inFileName);
Scanner scan = null;
int i = 0;
int[] num;
char[] rawInput;
try {
scan = new Scanner(inputFile);
while(scan.hasNextLine()) {
rawInput = scan.nextLine().toCharArray();
if(i == lineIndex) {
num = new int[rawInput.length];
for(int j = 0; j < num.length; j++) {
num[j] = rawInput[j] - '0';
}
scan.close();
return num;
}
i++;
}
} catch (Exception e) {
System.out.println("An error occurred while reading the numbers from file: ");
e.printStackTrace();
} finally {
if(scan != null)
scan.close();
}
return null;
}
private static void writeBigNumber(String outFileName, String num) {
try {
File outputFile = new File(outFileName);
FileWriter writer = new FileWriter(outputFile, false);
writer.write(num);
writer.close();
} catch (Exception e) {
System.out.println("An error occurred while writing the result: ");
e.printStackTrace();
}
}
我知道有许多其他算法可以做同样的事情并且比我的要好得多,但我想了解为什么这并不总是有效。提前致谢。
解决方案
您的错误在于您正在从具有多个数字的单元格中进行最终结转:
if(res[i] > 9) {
res[i - 1] += (res[i] / 10) % 10; //left-digit
res[i] = res[i] % 10; //right-digit
}
在这里,您假设res[i]
最多有两位数(不大于 99)。假设不成立。我尝试使用您的程序将 99 999 999 999(11 位数字)与自身相乘,res[12]
此时包含 100。所以(res[i] / 10) % 10
评估为 0,你没有携带任何东西res[11]
或res[10]
你应该携带任何东西。
我想我应该让自己找到一个好的解决方法。
编辑:为了可读性,这是您自己的评论,格式化和缩进的修复:
for (int i = res.length - 1; i >= 0; i--) {
if (res[i] > 9) {
if (res[i] > 99) {
res[i - 1] += ((res[i] / 100) % 10) * 10; // first digit (*10)
res[i - 1] += (res[i] / 10) % 10; // second digit
} else {
res[i - 1] += (res[i] / 10) % 10; // left-digit
}
res[i] = res[i] % 10; // right-digit
}
}
推荐阅读
- python - Django 未识别 URL 模式
- bash - 如何在不发送变量值的情况下从另一个脚本在脚本中写入变量?
- c++ - 有没有更简单的方法在 VSCode 中显示迭代器索引到向量?
- php - Laravel 8 和 Digitalocean 空间存储上传
- ruby - Ruby:尽管响应成功,但无法从时间迭代
- python - 如何使用 python 套接字从服务器接收多个列表?
- apache - 在 Ubuntu 上实现一个welcome.conf 文件
- python - 使用python中的字典列表提取元素
- .htaccess - htaccess 307 重定向,此文件应通过 HTTPS 提供
- sql - 在 SQL 中的两个字符之间拉取字符串的一部分,以及提取的部分周围的字符串部分