目录
高精度算法存在的理由主要就是因为数字太大,用int或者long不足以承受,所以可以通过使用数组或者vector来实现高精度的加减乘除算法。这个算法是需要面对题目来讲解的,所以后面讲解四个题目分别是高精度加减乘除。
高精度加法
给定两个正整数(不含前导 0),计算它们的和。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的和。
数据范围
1≤整数长度≤100000
输入样例:
12 23
输出样例:
35
实现高精度加法的基本思路是这样的:
-
创建两个vector,分别用来存储输入进来的数
-
从低位到高位加,注意进位,最后输出
但是要实现这个思路需要有一些注意点,比如说数据太大,不能用int从控制台把数据输入进来,所以需要使用string来保存输入的数据,用vector来保存最终的结果,但是如果要从小到大依次加,可能会发生进一位,所以需要让从控制台输入的数据按逆序保存在vector中,然后在进行加法。
下面是具体的代码:
#include<iostream>
#include<vector>
using namespace std;
const int N = 1e6 + 10;
vector<int> add(vector<int> &A, vector<int> &B){
vector<int> C;
int t = 0; // 用来保存是否进位
for(int i = 0; i < A.size() || i < B.size(); i++){
if(i < A.size()) t += A[i]; // 如果此时i的下标还没有超出A的范围就加
if(i < B.size()) t += B[i]; // 如果此时i的下标还没有超出B的范围就加
C.push_back(t % 10); // 余10是因为相加的结果可能会大于10
t /= 10; // 如果t大于10说明需要进一,所以结果就是下一次加会把这个进一也算上
}
if(t) C.push_back(1); // 此时如果t为0说明没有进位,如果t为1说明两个数相加后需要位数比二者都大
return C;
}
int main(){
string a, b; // 保存从控制台读取的两个数
vector<int> A, B; // 保存两个数的倒序
cin >> a >> b;
for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0'); // 把字符转换成整型
for(int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
auto C = add(A, B);
for(int i = C.size() - 1; i >= 0; i--) printf("%d", C[i]); // 输出结果
return 0;
}
高精度减法
题目:
给定两个正整数(不含前导 0),计算它们的差,计算结果可能为负数。
输入格式
共两行,每行包含一个整数。
输出格式
共一行,包含所求的差。
数据范围
1≤整数长度≤105
输入样例:
32 11
输出样例:
21
高精度减法也跟加法相差不多,只是它比加法多了判断两个数大小的操作。
基本的实现步骤:
-
从控制台读取需要相加的两个数,用vector保存这个数的倒序
-
判断两个数谁大,用大的数减去小的数
-
如果是小的数减大的数,在输出结果前需要先输出 “ - ”
注意点:
-
如果低位数借一需要让高位减一
-
最终得到的vector可能高位会有0,此时需要除去这些0,比如说下面这种情况
代码如下:
#include<iostream>
#include<vector>
using namespace std;
// 判断两个数的大小
bool cmp(vector<int> &A, vector<int> B){
if(A.size() != B.size()){ // 如果两个vector的大小不一样,直接比较二者的size即可
return A.size() > B.size();
}
for(int i = A.size() - 1; i >= 0; i--) // 如果二者的大小一样,就从高位到低位比较
if(A[i] != B[i]) return A[i] > B[i]; // 如果比较出来有一位两个数不一样,返回二者的比较
return true; // 到这里说明二者大小相同,用谁减谁都可以
}
vector<int> sub(vector<int> &A, vector<int> &B){
int t = 0; // 用于保存是否借位
vector<int> C; // 用于保存最终的结果
for(int i = 0; i < A.size(); i++){
t = A[i] - t; // 如果借位了,先让A[i]减去借的
if(i < B.size()) t -= B[i]; // 如果i此时还没有到B的末尾,就继续减
C.push_back((t + 10) % 10); // 如果二者相减结果小于0,需要借位,所以通过这种方式可以获取结果。如果大于0,按照这样的做法也不会有差。直接将两种可能结合
if(t < 0) t = 1; // 如果t小于0,说明借位了,把t设置成1
else t = 0; // 否则,说明不需要借位,设置为0
}
// 如果高位有0,需要除去
while(C.size() > 1 && C.back() == 0) // 这个判断保证了必须起码有一位,因为如果两个数相同,必须输出 0
C.pop_back();
return C;
}
int main(){
string a, b; // 用于保存从控制台读取的两个数
vector<int> A, B; // 用来保存读取的数的倒序
cin >> a >> b;
for(int i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0'); // 将字符转换成整型
for(int i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0');
if(cmp(A, B)){ // 如果a > b,此时用A减去B
auto C = sub(A, B);
for(int i = C.size() - 1; i >= 0; i--)
cout << C[i];
}else{ // 否则,用B减去A
auto C = sub(B, A);
cout << "-"; // 在输出结果前需要先输出 -
for(int i = C.size() - 1; i >= 0; i--)
cout << C[i];
}
return 0;
}
高精度乘法
题目:
给定两个非负整数(不含前导 0) A 和 B,请你计算 A×B 的值。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共一行,包含 A×B的值。
数据范围
1≤A的长度≤100000, 0≤B≤10000
输入样例:
2 3
输出样例:
6
注意点:输入的两个数一个数是很大的**,而第二个数是可以用long来存储的
实现步骤:
-
让A从个位到最高位乘以B
-
创建变量t,用来保存计算的结果,每当用A的一位乘以B后,就将这个数加到t上,然后把t%10在存到新的vector中
-
循环结束的条件是用A的每一位都乘以B了并且t的值为0
代码实现:
#include<iostream>
#include<vector>
using namespace std;
vector<int> mul(vector<int> &A, int b){
int t = 0; // 用来保存进行乘法的结果
vector<int> C; // 用来保存最终的输出
for(int i = 0; i < A.size() || t; i++){ // 如果A中的所有数还没有都用到或者t不为0,就继续循环
if(i < A.size()) t += A[i] * b; // 如果此时还没有用A的最高位乘以b,就把乘法的结果加到t上
C.push_back(t % 10); // 把t%10的结果保存到C中
t /= 10; // 除去t的最后一位
}
// 把多余的0除去
while(C.size() > 1 && C.back() == 0){
C.pop_back();
}
return C;
}
int main(){
string a; // 用来存储大的数
int b; // 存储较小的那个数
cin >> a >> b;
vector<int> A; // 用来保存a中的数据
for(int i = a.size() - 1; i >= 0; i--){
A.push_back(a[i] - '0'); // 使a倒序并把字符转换成整型
}
vector<int> C = mul(A, b); // 获取结果
for(int i = C.size() - 1; i >= 0; i--){
cout << C[i]; // 输出结果
}
return 0;
}
高精度除法
题目:
给定两个非负整数(不含前导0) A,B,请你计算 A/B 的商和余数。
输入格式
共两行,第一行包含整数 A,第二行包含整数 B。
输出格式
共两行,第一行输出所求的商,第二行输出所求余数。
数据范围
1≤A的长度≤100000, 1≤B≤10000, B 一定不为 0
输入样例:
7 2
输出样例:
3 1
步骤:
-
从高位到低 位除以除数,直到A中的所有数都用到了
-
将除后的结果保存到vector中,取得的余数保存到r中
-
具体的还得落实到代码中,代码中详细说明了这些步骤的原因以及作用
代码实现:
下面这幅图是对除法循环中进行的步骤的解释:
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
vector<int> div(vector<int> &A, int b, int &r){
vector<int> C; // 保存计算的结果
r = 0; // 将余数重置为0
for(int i = A.size() - 1; i >= 0; i--){
r = r * 10 + A[i]; // 计算本次要被除的数
C.push_back(r / b); // 将本次除法的结果保存
r %= b; // 获取余数
}
reverse(C.begin(), C.end()); // 计算的结果是按照从大到小的顺序保存到C中的,所以需要将它倒序
while(C.size() > 1 && C.back() == 0){ // 除去多余的0
C.pop_back();
}
return C;
}
int main(){
string a; // 保存被除的数
int b; // 保存除数
cin >> a >> b;
vector<int> A; // 用于存储被除的数
for(int i = a.size() - 1; i >= 0; i--){
A.push_back(a[i] - '0'); // 将字符装换成整型
}
int r; // 用于保存余数
auto C = div(A, b, r); // 计算结果
for(int i = C.size() - 1; i >= 0; i--){ // 输出结果
cout << C[i];
}
cout << endl << r << endl;
return 0;
}
以上就是本次高精度算法的全部,如果有错误欢迎指出,或者有什么不足欢迎来讨论。