高精度定义
高精度计算(Arbitrary Precision Arithmetic)是指超过编程语言内置数据类型(如 int、long、double)所能表示范围的数值运算。一般编程语言的数值类型有固定的存储位数,导致超出范围时可能溢出或丢失精度,因此需要使用高精度算法来处理。
出现的原因:
- 1️⃣ 存储空间限制:int、double 等数据类型有固定的存储位数,超出范围会溢出或丢失精度。
- 2️⃣ 浮点数误差:计算机采用二进制存储小数,导致某些十进制数无法精确表示。
- 3️⃣ 科学/金融计算需求:很多实际应用(如金融、密码学)要求精确到几十位甚至上百位,普通数据类型无法满足
高精度模板套用:
Tip:
inline 是 C++ 关键字,用于建议编译器将函数代码直接插入调用处,以减少函数调用的开销,提高执行效率
- 普通函数调用涉及 压栈、跳转、返回 等步骤,inline 通过内联展开(直接替换代码)避免了这些额外操作,提高执行速度 ;
- 适合短小的函数,不适合递归函数和复杂函数;
vector<?> 为C++标准模板库中的动态数组容器;
特点:
- 支持自动扩容,调整大小;
- 连续存储,可以用指针遍历
- 支持随机访问;
方法:
- vector v(5, 10); // 创建 5 个元素,初始值均为 10
- vector v(5); // 定义一个大小为 5,所有元素初始化为 0 的 vector
- v.push_back(4); // {1, 2, 3, 4},在末尾添加 4
- v.insert(v.begin(), 0); // {0, 1, 2, 3, 4},在开头插入 0
- v.pop_back(); // 删除最后一个元素 {0, 1, 2, 3}
- v.erase(v.begin()); // 删除第一个元素 {1, 2, 3}
- int last = v.back(); // 访问最后一个元素
- int size = v.size(); // 获取元素个数
- reverse(res.begin(), res.end());//翻转数组中元素的位置 ,使用时加上 algorithm 头文件
高精度加法
思路:
- 传入两个动态数组,先在调用方法设置一个空的动态数数组和一个标志进位的值;
- 然后for循环其两个动态数组的长度,然后依次从其数组的低位加起来到标志进位的值;
- 然后将得到的值进%10取余做累加值的低位,然后将低位加起来的值/10保留到标志进位的值;
- 然后进行后续的操作,直到没有进位或者for循环达到索引是两个动态数组的长度;
/**
*这里的传入的数据方向是高位到低位
*/
inline vector<int> add(vector<int> &a, vector<int> &b) {
vector<int> res;
int carry = 0; // 进位
int lenA = a.size(), lenB = b.size();
// 从高位到低位处理
for (int i = 0; i < max(lenA, lenB) || carry; i++) {
if (i < lenA) carry += a[lenA - 1 - i]; // 从高位开始加
if (i < lenB) carry += b[lenB - 1 - i]; // 从高位开始加
res.push_back(carry % 10); // 取当前位
carry /= 10; // 更新进位
}
reverse(res.begin(), res.end()); // 反转结果以恢复高位在前
return res; // 返回最终结果
}
高精度减法
思路:
- 创建一个存储结果的向量和一个借位的临时变量;
- 从数值的低位开始进行相减,然后当数值小于0时进行借位;
- 将计算后的借位值插入存储结果的向量后面,以此类推;
- 最后对于前导0进行置空,以及翻转结果向量;
/**
*这里的传入的数据方向是高位到低位
*/
inline vector<int> sub(vector<int> &a, vector<int> &b) {
vector<int> res;
int borrow = 0; // 借位
int lenA = a.size(), lenB = b.size();
// 从高位到低位处理
for (int i = 0; i < lenA; i++) {
int t = a[lenA - 1 - i] - borrow; // 从高位开始减去借位
if (i < lenB) {
t -= b[lenB - 1 - i]; // 减去 b 的当前位
}
if (t < 0) {
t += 10; // 借位
borrow = 1;
} else {
borrow = 0;
}
res.push_back(t); // 存储当前位的结果
}
// 去掉前导零
while (res.size() > 1 && res.back() == 0) {
res.pop_back();
}
reverse(res.begin(), res.end()); // 反转结果以恢复高位在前
return res;
}
高精度乘法(高精度数组,低位数值相除)
思路:(这里建议书写一个乘法运算,240*3)
- 传入高精度数组和对应的另一个低精度的乘数;
- 创建一个存储结果的动态数组和一个标志进位;
- 遍历从高精度低位开始依次乘以低精度乘数,然后模拟高精度加法进行取余放低位,剩下进行取模
- 依次循环往复,直到索引到达动态数组高位;
/**
*这里的传入的数据方向是高位到低位
*/
inline vector<int> mul(vector<int> &a, int b) {
vector<int> res; // 存储结果的向量
int t = 0; // 进位
int len = a.size(); // 输入向量的长度
for (int i = len - 1; i >= 0; i--) { // 从高位到低位处理
t += a[i] * b; // 乘以 b
res.push_back(t % 10); // 取当前位
t /= 10; // 更新进位
}
while (t) { // 处理剩余的进位
res.push_back(t % 10);
t /= 10;
}
reverse(res.begin(), res.end()); // 反转结果以恢复高位在前
return res; // 返回乘法结果
}
高精度除法(高精度数组,低位数值相除)
思路:(这里建议书写一个除法运算240/3)
- 初始先创建存储结果的向量和余数变量;
- 循环遍历从高位开始,进行余数*10再加向量中的索引位;
- 进行判断余数是否大于被除数,如果是进行push其相除的计算结果,后更新余数;否则更新余数为0;
- 去除前导0并最后返回结果;
/**
*这里的传入的数据方向是高位到低位
*/
inline vector<int> div(vector<int> &a, int b) {
vector<int> res; // 存储结果的向量
int r = 0; // 余数
int len = a.size(); // 输入向量的长度
for (int i = 0; i < len; i++) { // 从高位到低位处理
r = r * 10 + a[i]; // 将当前位加入余数
if (r >= b) { // 如果余数大于等于除数
res.push_back(r / b); // 计算商并存入结果
r %= b; // 更新余数
} else {
res.push_back(0); // 商为0
}
}
// 去掉前导零
while (res.size() > 1 && res.front() == 0) {
res.erase(res.begin()); // 移除前导零
}
return res; // 返回除法结果
}
高精度比较
思路:
- 先进行动态数组长度的判断;
- 长度相同依次从每一个位进行比较;
inline int compare(vector<int> &a, vector<int> &b) {
int lenA = a.size();
int lenB = b.size();
if (lenA != lenB) { // 长度不同
return lenA - lenB; // 返回长度差
} else { // 长度相同
for (int i = lenA - 1; i >= 0; i--) {
if (a[i] != b[i]) { // 从高位比较
return a[i] - b[i]; // 返回差值
}
}
return 0; // 相等
}
}
1566

被折叠的 条评论
为什么被折叠?



