大数乘法
食用指南:
对该算法程序编写以及踩坑点很熟悉的同学可以直接跳转到代码模板查看完整代码
只有基础算法的题目会有关于该算法的原理,实现步骤,代码注意点,代码模板,代码误区的讲解
非基础算法的题目只有题目分析,代码实现,代码误区
题目描述:
-
给定两个非负整数(不含前导 0) A 和 B,请你计算 A×B 的值。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。输出格式
共一行,包含 A×B 的值。数据范围
1≤A的长度≤100000,
0≤B≤10000
输入样例:
2
3
输出样例:
6 -
题目来源:https://www.acwing.com/problem/content/795/
题目分析:
- 数据A的长度最高达到了100000,属于大数
- 数据B属于正常数
- 本题属于基础的大数乘法
算法原理:
- 关于大数定义和输入输出问题详见我在大数加法和大数减法中的内容:传送门
大数乘法:
-
含义:大数乘法指的是大数乘以一个正常大小的数,并不是两个大数相乘
-
来源:大数乘法和大数加法极为相似,区别在于大数乘法的进位不止于1,而且正常数为0时引入前导0
-
第i位上的数:
当前位 = (上次进位 + 正常数 * 大数位) % 10; -
进位记录:
进位 = (上次进位 + 正常数 * 大数位) / 10; -
最高位:
上次进位不为0则继续进位 -
前导0:
只有0乘大数造成最高位出现前导0
写作步骤:
1. 输入输出问题:
- 大数先入string,逆序输入vector<int> A;
- 正常数直接入int N;
2. 乘法模拟:
- 进位不为0则需要一直循环
- 全局变量 t 维护每一位的进位结果
- 当前位计算公式 & 当前进位计算公式
3. 前导0的去除:
- 从C.size() - 1到0逆向检查前导零
- 前导0:C.back()==0 && C.size()>1
核心算法:
- 两个公式:
- 当前位 = (上次进位 + 正常数*大数位) / 10;
- 当前进位 = (上次进位 + 正常数*大数位) %10;
- 循环填写结果向量C[i]
- 填写过程<A.size() -> t+=A[i]*B; C.push_back(t % 10);
- 填写过程>= A.size(),即最高位不断进位 -> C.push_back(t % 10);
- 🌟最技术的点:进位 影响 循环终止条件
- 🌟最容易忘记的点:消除最高位的0 (前导0)
代码注意:
- 填写结果vector的循环终止条件:
- 起初填写的是大数的所有位
- 后来填写的是进位导致的最高位增加
- 较高位可能没有A[i]*B,只有进位t %10
结果填写在被乘数A内的位数有(A[i]*B+t)%10
否则只有 t % 10 - 容易忘记去除前导0
代码模板:
#include <iostream>
using namespace std;
vector<int> mul(vector<int> &A, int b){
vector<int> V;
int t = 0;
//注意点2:循环终止条件既看有限位,又看进位
for(int i=0; i<A.size()||t; i++){
if(i<A.size()) t+=A[i]*b;
C.push_back(t % 10);
t /= 10;
}
//注意点3:0*大数产生很多位0,需要删除
while(C.size() > 1 && C.back()==0)
C.pop_back();
return C;
}
int main(){
string a;
int B = 0;
cin >> a >> B;
vector<int> A;
for(int i=a.size()-1; i>=0; i--){
A.push_back(a[i] - '0');
}
vector<int> C = (A,B);
for(int i=C.size()-1; i>=0; i--){
cout << C[i];
}
return 0;
}
代码误区:
1. 循环终止条件两者缺一不可:
for(int i=0; i<A.size()||t; i++){
}
因为只要t不为0 则最高位需要一直进位
如:计算到A.size()-1时,结果为a
此时t = 432
则需要再进三位,结果是a234
2. 进位t最大是9吗?
大数乘法的进位来源起初是A[i]*B,可以是很大的正常数,不像大数加法结果最大进位1,此处可能一个乘积就进位3位。
本篇感想:
- 高精度乘法主要是记住两个公式(当前位&进位),以及两个易错点(循环终止条件&前导0去除)
- 其实大数加法和减法也主要说公式,但是初步学习高进度还是具象一点去模拟理解吧
- 大数加法公式:
当前位 = (A[i]+B[i]+t) % 10;
进位 t = (A[i] + B[i] + t) / 10; - 大数减法公式:
当前位 = (A[i] - t - B[i] + 10) % 10;
借位 t = A[i]-t-B[i] <0 ? 1 : 0; - 看完本篇博客,恭喜已登《练气境-初期》
距离登仙境不远了,加油