模拟法
思路
模拟小学学习的列竖式的方式计算大数,
采用先相加,存储到每一列对于的位子,最后再进位的方式简化计算
9 8
× 2 1
-------------
(9)(8) <---- 第1趟: 98×1的每一位结果
(18)(16) <---- 第2趟: 98×2的每一位结果
-------------
(18)(25)(8) <---- 这里就是相对位的和,还没有累加进位
此处先不考虑进位,先相加得18、25、8,存储在结果的相应位子,最后从右往左,若结果大于10,向左边进位
思路简单,朴实,易于实现
代码实现
#include <iostream>
using namespace std;
class Node {
public:
Node() {
length = 0; //大数的长度
memset(s, 0, sizeof(s));
}
Node(char*str) { //用char初始化,方便使用
int i = 0;
memset(s, 0, sizeof(s));
while (str[i] != '\0') //当不为空时
{
s[i] = str[i] - '0'; //将str的每一位转化为int型存入s数组
++i; //由于从左到右,小标越小,幂此越大
}
length = i;
}
int length;
int s[2000];
void bigNumberMultiply(Node num1, Node num2, Node &result) { //计算函数
result.length = num1.length + num2.length; //result为最后的结果,参数引用
for (int i = 0; i < num1.length; i++) //两个for循环模拟竖式计算过程
for (int j = 0; j < num2.length; j++)
result.s[i + j + 1] += num1.s[i] * num2.s[j]; //注释1
for (int k = result.length - 1; k > 0; k--) //注释2
if (result.s[k] > 10) {
result.s[k - 1] += result.s[k] / 10;
result.s[k] %= 10;
}
}
};
char str[2000];
int main() {
cout << "请输入大数a和b:" << endl;
cin >> str;
Node a(str);
cin >> str;
Node b(str);
Node result;
result.bigNumberMultiply(a, b, result);
for (int i = 0; i < result.length; i++) {
if (i == 0 && result.s[i] == 0)continue; //一开始全部初始化为0,防止第一位有0
cout << result.s[i];
}
}
- 注释1(代码第26行)
`见思路中的计算过程,由于下标越小,幂此越大,因此不同于平常计算时从右往左的习惯,这里我们从左往右看,每一趟的左边都要空出i+j个空位,这里之所以i+j又加了1,是为了将s数组的第一位空出来,防止最高位,也就是最左侧那一位的累加结果需要进位的话,result[]数组就没有空间存放了。- 注释2(代码第28行)
改for循环用于进位,由于下标越小,幂此越大,因此从最大下标开始往小的下标进位
分治法
思路
将大数X和Y进行拆分,可将XY简化成下图最后一行式子,看起来复杂,实际降低了复杂度
不断拆分,直到只有一位时,可直接进行相乘
#include<cstdio>
#include<cmath>
using namespace std;
#define SIGN(A) ((A > 0) ? 1 : -1) //判断正负
int divideConquer(int X, int Y, int n) { //n位长度的X和Y相乘(此处XY长度相同)
int sign = SIGN(X) * SIGN(Y); //判断正负
int x = abs(X);
int y = abs(Y);
if (x == 0 || y == 0) {
return 0;
}
else if (n == 1) { //当只有一位时,停止递归,输出相乘的值
return sign * x * y;
}
else {
int A = (int)x / pow(10, (int)(n / 2)); //整除取高位
int B = x - A * pow(10, n / 2); //x直接减去高位,得出低位
int C = (int)y / pow(10, (int)(n / 2));
int D = y - C * pow(10, n / 2);
//根据公式要求,分别计算出AC、BD、ABDC
int AC = divideConquer(A, C, n / 2);
int BD = divideConquer(B, D, n / 2);
int ABDC = divideConquer((A - B), (D - C), n / 2) + AC + BD;
return sign * (AC * pow(10, n) + ABDC * pow(10, (int)(n / 2)) + BD);
}
}
int main() {
int x, y, n;
scanf("%d%d%d", &x, &y, &n);
printf("x 和 y的乘积为:%d", divideConquer(x, y, n));
}
}