给出两个非负整数,求它们的乘积。
输入共两行,每行一个非负整数。
输出一个非负整数表示乘积。
1
2
2
每个非负整数不超过 1 0 2000 10^{2000} 102000。
输入两个数,计算乘积。
因为是大数运算,所以直接算肯定超数据类型范围。
这里同样和两数之和的高精度一样,使用字符数组输入后,
根据两数乘积运算法则进行相关计算。
由于字符串数组输入两个数字存在长度不一致,导致运算错位的问题,
这里提供两种解决思路:
第一,前置补零运算,让长度较短的数前面补零和长度较长的数长度一致。
只是后续输出结果,处理起来比较麻烦,涉及到进位问题,需要将结果数组元素后移的问题。
第二,将输入的两个数逆序存储到整型数组中,这样就保证了运算位对位正确,然后将每一轮计算结果累加到结果数组的相应位置,再让大于9的元素进位,这样就得到了同样逆序的结果,再将结果逆序输出即可。
本题代码采用第二种方式计算。
举个例子:当计算1234 * 789时,必然涉及到进位问题,
(1)先让两个数逆序:
4 3 2 1
9 8 7 0
(2)然后将每一轮结果累加得到逆序但未进位的输出:
36 59 70 46 22 7
(3)依次进位:
6 2 6 3 7 9
(4)逆序输出:
973626
输出两个字符串,获取输入的字符长度,
反转存入整型数组,目的是,当两个乘数的长度不一致时,反转之后每一次计算的位置不会受到影响,
反转过程中,减去字符’0’,赋值给对应整型数组。
然后进行上述分析中的两数相乘运算,将任一一位乘数的一位与另一个乘数的每一位相乘,
结果累加在另一个数组相应的位置,计算出的是未进位的逆序结果。
接下来就是进位操作:
这里循环的次数为两个乘数的长度和,因为两数之积的位数不会大于原本两数的长度之和。
当元素大于9时,先进位,因为是逆序,前一位数字就是现在数组的后一位,后计算余数 即当前位。
结束后,逆序(当第一次遇到非零数字后,开始输出)打印输出即可。
值得一提的是,需要特判零:
当上述遍历全为零时,则结果为零,打印零即可。
#include
#include
using namespace std;
int main() {
//用于输入
char a[2001], b[2001];
//整型数组用于计算
int a1[2001], b1[2001], m1[4001];
//输入两个大数
cin >> a >> b;
//获取输入的字符长度
int len1 = strlen(a);
int len2 = strlen(b);
//反转存入整型数组
//目的是,当两个乘数的长度不一致时,反转之后每一次计算的位置不会受到影响
for (int i = 0; i < len1; ++i) {
//减去字符'0',赋值给对应整型数组
a1[i] = a[len1 - 1 - i] - '0';
}
for (int i = 0; i < len2; ++i) {
b1[i] = b[len2 - 1 - i] - '0';
}
//两数相乘:将任一一位乘数的一位与另一个乘数的每一位相乘,
// 结果累加在另一个数组相应的位置
for (int i = 0; i < len1; ++i) {
for (int j = 0; j < len2; ++j) {
//数学规律:计算出的是未进位的逆序结果:
// 例如12*12 在这里的结果就是4 4 1,实际结果逆序为144即可。
m1[i + j] += a1[i] * b1[j];
}
}
//进位
//两数之积的位数不会大于原本两数的长度之和
for (int i = 0; i < len1 + len2; ++i) {
//满十进几
if (m1[i] > 9) {
//先进位,因为是逆序,前一位数字就是现在数组的后一位
m1[i + 1] += m1[i] / 10;
//计算余数 即当前位
m1[i] %= 10;
}
}
//标记符
int cnt = 1;
//逆序输出:当第一次遇到非零数字后,开始输出
for (int i = len2 + len1; i >= 0; i--) {
//判断非零
if (m1[i] != 0 && cnt == 1) {
cnt--;
}
//输出
if (cnt == 0) {
cout << m1[i];
}
}
//特判零:当上述遍历全为零时,则结果为零,打印零即可。
if (cnt == 1) {
cout << 0;
}
return 0;
}