前言
在我个人看来,其实高精度算法就是把我们手算加减乘除的思维过程模拟了一边,所以如果不记得的话不如手算一遍,看看自己是如何处理每个数字的。
一、高精度加法
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
// 定义一个函数实现大整数加法
vector<int> add(vector<int> a, vector<int> b){
if(a.size() < b.size()) return add(b, a); // 确保a的长度不小于b的长度
vector<int> temp;
int carry = 0; // 进位,初始为0
for(int i = 0; i < a.size(); i++){
if(i < b.size()) carry += b[i]; // 如果b还有位数,加上对应位的数字
carry += a[i]; // 加上a对应位的数字
temp.push_back(carry % 10); // 将个位数字加入结果中
carry /= 10; // 更新进位
}
if(carry) temp.push_back(carry); // 最后如果还有进位,加入结果中
// 去除前导0
while(temp.size() > 1 && temp.back() == 0) temp.pop_back(); // 去除前导0
reverse(temp.begin(), temp.end()); // 将结果反转,使得高位在前
return temp;
}
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');
// 调用 add 函数进行大整数加法
vector<int> result = add(a, b);
// 输出相加的结果
for(int i = 0; i < result.size(); i++) cout << result[i];
return 0;
}
二、高精度减法
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// 比较a和b的大小,若为true,则表示a大于b
bool cmp(vector<int> a, vector<int> b) {
if (a.size() != b.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) {
vector<int> temp;
int t = 0;
for (int i = 0; i < a.size(); i++) {
t = a[i] - t; // 从a的当前位减去借位
if (i < b.size()) t -= b[i]; // 若b还有位数,则继续减去b的对应位
temp.push_back((t + 10) % 10); // 将结果加入到temp中
if (t < 0) t = 1; // 如果需要借位,则将t设为1
else t = 0; // 否则不需要借位
}
// 去除temp末尾的多余0
while (temp.size() > 1 && temp.back() == 0) temp.pop_back();
reverse(temp.begin(), temp.end()); // 将temp翻转得到最终结果
return temp;
}
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');
vector<int> result;
// 如果a大于b,则直接进行减法运算
if (cmp(a, b)) {
result = sub(a, b);
}
// 如果a小于b,则输出负号,并进行减法运算
else {
result = sub(b, a);
cout << "-";
}
// 输出最终的结果
for (int i = 0; i < result.size(); i++) cout << result[i];
return 0;
}
三、高精度乘法
1.高精度乘以低精度
思路
假设我们要求345x67
先来理解一个十进制数的本质
345=3x100+4x10+5
那么
345x67
=(3x100+4x10+5)x67
=(3x100x67)+(4x10x67)+(5x67)
所以我们求出5x67=335之后,很容易能想到,个位只会保留5,而330会加到更高位上。
即4x10x67要加上330
都除以10,就得到4x67加上33
所以可以得出,计算过程为:
从低位开始,获取A的一位,与b相乘,结果的个位留在这一位,结果除以10后加到下一位
这样循环直到A的最高位
手算过程如下图:
其中蓝色小圆圈保留在该位,横线进入下一位。
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
// 定义一个函数 mul,用于实现大整数乘法
// 参数 a: 存储大整数的向量
// 参数 b: 乘数
// 返回值: 乘积的向量
vector<int> mul(vector<int> a, int b){
vector<int> res; // 保存乘积的向量
int temp = 0; // 用于存储进位
// 逐位进行乘法运算
for(int i = 0; i < a.size() || temp; i++){
if(i < a.size()) temp = temp + a[i] * b; // 乘数与当前位相乘并加上进位
res.push_back(temp % 10); // 将个位数字存入结果向量
temp /= 10; // 更新进位
}
// 去除前导0
while(res.size() > 1 && res.back() == 0) res.pop_back(); // 去除前导0
reverse(res.begin(), res.end()); // 反转结果向量,得到正确顺序
return res;
}
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'); // 倒着插入,因为乘法要从低位开始运算
vector<int> result = mul(a, b); // 调用 mul 函数进行乘法运算
// 输出乘积
for(int i = 0; i < result.size(); i++) cout << result[i];
return 0;
}
2.高精度乘以高精度
思路
高精度乘以高精度,就不能用刚刚的方法了。
既然是高精度,那么就只能单个数乘以单个数,比如1x1,3x6,而不能是12x3。
但是得到的结果放在哪里呢?
让我们找一下规律。
可以发现,a[i]乘以b[j],结果要放在c[i+j]
但是进位怎么办?
很简单,只要先用c数组存储临时结果,最后一步再进位就可以啦
下面代码的temp数组就相当于这里的C数组
代码
#include<iostream>
#include<vector>
using namespace std;
// 定义一个函数 mul,用于实现大整数乘法
// 参数 A: 第一个大整数的向量形式
// 参数 B: 第二个大整数的向量形式
// 返回值: 乘积的向量
vector<int> mul(vector<int> A, vector<int> B){
vector<int> temp(A.size() + B.size() + 8, 0); // 临时向量存储乘积结果,预留足够的空间
for(int i = 0; i < A.size(); i++){
for(int j = 0; j < B.size(); j++){
temp[i + j] += A[i] * B[j]; // 计算乘积并累加到正确的位置
}
}
//temp数组进位
int t = 0;
for(int i = 0; i < temp.size(); i++){
t += temp[i];
temp[i] = t % 10; // 取个位作为当前位置的值
t /= 10; // 更新进位
}
// 去除前导0
while(temp.size() > 1 && temp.back() == 0) temp.pop_back(); // 去除前导0
return temp;
}
int main(){
string a, b;
cin >> a >> b; // 输入两个大整数
vector<int> A, B;
int i;
for(i = a.size() - 1; i >= 0; i--) A.push_back(a[i] - '0'); // 将第一个大整数转换为向量形式存储
for(i = b.size() - 1; i >= 0; i--) B.push_back(b[i] - '0'); // 将第二个大整数转换为向量形式存储
auto C = mul(A, B); // 调用 mul 函数进行乘法运算
// 输出乘积
for(int i = C.size() - 1; i >= 0; i--) cout << C[i];
return 0;
}
四、高精度除法
1.高精度除以低精度
思路
假设我们要手算除法,那么接下来应该列一个竖式。
以23456除以12为例,及A=23456,b=12
以下为手算过程,标识符对应第2部分的代码:
(1)首先,用23456的第一个数2除以12,得0,余数为2。
那么这个余数就要乘以10后,加在下一步的计算中
r = r*10 + A [ 1 ] 即 r = 2x10 + 3 = 23
(2)接着,用r=23除以b,得1,余数为11
下一步11要乘以10,加上A[2]=4,得114
……
由于时间原因 (我懒) ,只写了前三步,后面类似。
注意:最后要去除前导0,所以先将vector翻转,pop_back出最后的0,再翻转回来。
代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
// 定义一个函数 div,用于实现大整数除法
// 参数 a: 存储被除数的向量
// 参数 b: 除数
// 参数 r: 余数,通过引用传递以在函数外部访问
// 返回值: 商的向量
vector<int> div(vector<int> a, int b, int& r){
vector<int> temp;
for(int i=0; i<a.size(); i++){
r = a[i] + r * 10; // 将上一次计算的余数乘以10再加上当前位的数字
temp.push_back(r / b); // 计算商并存入临时向量
r %= b; // 计算新的余数
}
// 去除前导0
reverse(temp.begin(), temp.end()); // 反转临时向量
while(temp.size() > 1 && temp.back() == 0) temp.pop_back(); // 去除前导0
reverse(temp.begin(), temp.end()); // 恢复顺序
return temp;
}
int main(){
string A;
int b;
cin >> A >> b; // 输入被除数和除数
vector<int> a;
for(int i=0; i<A.size(); i++) a.push_back(A[i]-'0'); // 将被除数转换为向量形式存储
int r = 0; // 余数
auto result = div(a, b, r); // 调用 div 函数进行除法运算
// 输出商
for(int i=0; i<result.size(); i++) cout << result[i];
// 输出余数
cout << endl << r;
return 0;
}
2.高精度除以高精度
先睡个午觉,待会更
zzz~