C++的高精度乘法
2023-09-03 11:30:00
发布于:广东
为什么需要高精乘
在其它的编程语言里(如Python和Java)都直接支持高精度数据。而对于 C++ 而言,最大的数据为 long long(64b,8位),对于超过 8B 的数据,C++ 没有对应的数据类型进行表示。所以我们需要知道如何进行高精度计算。
可以参考这个网页
高精度乘法原理
我们就可以用 C++ 语言来模拟这个竖式减法的过程。我们可以考虑利用 C++ 的数组来存储对应数据,假设用数组 A 存储被减数 856 的每一位,具体来说就是 A1 存储个位 6,A2 存储十位 5,A3存储百位 8;类似数组 A 的结构,使用数组 B 存储减数 25;类似数组 A 的结构,使用数组 C 来存储对应的乘积 21400。两数相加的结果就如图 2 所示。这样理论上来说,我们就可以计算无限大的数据。如上图 2 所示,下表表示对应的存储方式。
数组A | 数组B | 数组C | |
---|---|---|---|
[0] | 6 | 5 | 0 |
[1] | 5 | 2 | 0 |
[2] | 8 | 4 | |
[3] | 1 | ||
[5] | 2 |
如上面的图 2 ,首先计算被乘数与乘数的个位数字的乘积,把结果保存到积数组中,然后再用被除数乘以乘数的十位数字,把结果退一位加到积数组中。每加一次乘积结果就进行一次进位处理,放在一个新组数里面。其方法与加法中的进位处理一样。
x
x x
x x
x x
关键点
- a[i]*b[j] 应该累加到 i+j 的位置;
- 累加总结果为: c[i+j] = a[i]*b[j]+jw+c[i+j];
- 所以每次累加完后:
(1)带入下一位累加的进位: jw = c[i+j] / 10;
(2)本位实际数: c[i+j] %= 10。
高精度乘法实现
思路
- 定义存储数组。
- 读入数据处理。
- 从个位开始模拟竖式乘法的过程,完成整个乘法。
- 删除前导 0 。所谓前导零,就是出现类似这样数据 01234,这个 0 实际是不需要的。
- 输出结果。倒序输出减法的结果数组 C,因为我们的个位是存储在下标为 0 的地方。
技术细节说明
定义存储数组
根据题目的要求定义数组,部分代码如下:
const int MAXN = 1e5+4; //根据题目的最大值。+4为了防止A+B出现进位
char s1[MAXN] = {};//存储字符串
char s2[MAXN] = {};//存储字符串
int a[MAXN] = {};//存储加数A
int b[MAXN] = {};//存储加数B
int c[2*MAXN] = {};//存储乘积
读入数据并处理
这里我们先考虑以下几种情况,即 -35=-15 或者 -48=-32 或者 -3*(-2)=6,也就是说,需要对输入数据的正负号进行判断。这个部分代码
如下:
scanf("%s %s", s1, s2);//读入字符串
//处理负数
bool flaga = false;//乘数a的符号
if ('-'==s1[0]) {
flaga = true;
strcpy(s1, &s1[1]);//删除负号
}
bool flagb = false;//乘数b的符号
if ('-'==s2[0]) {
flagb = true;
strcpy(s2, &s2[1]);//删除负号
}
//处理输出的负号
if ((true==flaga && false==flagb) || (false==flaga && true==flagb)) {
printf("-");
}
//处理乘数1
int lena = strlen(s1);
for (int i=0; i<lena; i++) {
a[lena-i-1]=s1[i]-'0';
}
//处理乘数2
int lenb = strlen(s2);
for (int i=0; i<lenb; i++) {
b[lenb-i-1]=s2[i]-'0';
}
模拟竖式乘法
这个部分的代码如下:
//模拟竖式乘法
int jw;//上一轮计算进位
for (int i=0; i<lena; i++) {
jw=0;
for (int j=0; j<lenb; j++) {
//交叉乘积
c[i+j] = a[i]*b[j]+jw+c[i+j];//当前乘积+上次乘积进位+原数
jw = c[i+j]/10;//处理进位
c[i+j] %= 10;
}
c[i+lenb]=jw;//进位设置
}
删除前导0
这个部分的代码如下
//删除前导零
int lenc=lena+lenb;
for (int i=lenc-1; i>=0; i--) {
//因为我们是从索引 0 开始,所以最高位是保存在 len-1
if (0==c[i] && lenc>1) {
//注意要有 lenc>1 这个条件。考虑特殊情况,加法结果为 00,我们实际要输出 0。
lenc--;
} else {
//第一个不是零的最高位,结束删除
break;
}
}
输出计算结果
采用倒序的方式输出,因为我们数据保存是倒序结构,也就是低位在前。
//逆序打印输出
for (int i=lenc-1; i>=0; i--) {
printf("%d", c[i]);
}
printf("\n");
这里空空如也
有帮助,赞一个