宇宙免责申明:
- 本文由deepseek做过更改,以及进行了语言上的优化,可能会出现错误,如有错误,请私信联系.
- 目前高精度加法的先别抄,可能有问题.
高精度计算四则运算模板详解(C++)
在 C++ 中,内置整数类型(int、long long)能表示的数值范围有限(long long 最大约 9.22×10189.22\times 10^{18}9.22×1018)。当我们需要处理远超此范围的整数(例如几百位的大数)时,就必须用数组或字符串模拟手算过程,这就是高精度计算。
本文基于我常用的四份模板代码,分别实现高精度加法、减法、乘法 (高精×高精)以及高精度除以低精度(高精÷低精,返回商和余数)。所有代码均以字符串读入,输出字符串结果,逻辑清晰,适合竞赛或工程使用。
总思路:模拟竖式的加减乘除的方法.
一、高精度加法
思路
模拟竖式加法:
- 将两个数字字符串按从低位到高位 (即个位在前)存入
vector<int>。 - 从低位到高位逐位相加,同时维护进位
jw。 - 每一位结果为
(a[i] + b[i] + jw) % 10,进位为/10。 - 最后如果进位非零,补到最高位。
- 将结果倒序转回字符串。
代码(函数模板)
cpp
#include <bits/stdc++.h>
using namespace std;
string a, b;
string gjadd(string x, string y)
{
int lenx = x.size(), leny = y.size();
int cs = max(lenx, leny); // 最长的位数
vector<int> a, b, sum;
// 倒序存储,个位在 index 0
for (int i = lenx - 1; i >= 0; i--)
a.push_back(x[i] - '0');
for (int i = leny - 1; i >= 0; i--)
b.push_back(y[i] - '0');
int tmp = 0, jw = 0;
for (int i = 0; i < cs; i++)
{
tmp = jw;
if (i < lenx) tmp += a[i];
if (i < leny) tmp += b[i];
jw = tmp / 10;
sum.push_back(tmp % 10);
}
if (jw != 0) sum.push_back(jw); // 最高位进位
string ans = "";
for (int i = sum.size() - 1; i >= 0; i--)
ans += char(sum[i] + '0');
return ans;
}
int main()
{
cin >> a >> b;
cout << gjadd(a, b);
return 0;
}
注意
- 无需去除前导零(加法不会产生多余零,除非
0+0=0,此时保留一个0是合理的)。 - 支持任意长度,只需内存足够。
二、高精度减法
思路
模拟竖式减法,但需要先判断结果符号:
- 若被减数小于减数(长度短,或长度相等且字典序小),则交换两数,并在答案前加负号
"-"。 - 将两数倒序存入
vector。 - 从低位到高位逐位相减,若不够减则向高位借位(
jw=1,当前位加 10)。 - 最后去除结果向量末尾的多余零(前导零)。
- 倒序输出,若之前标记了负号则先加上。
代码(函数模板)
cpp
#include <bits/stdc++.h>
using namespace std;
string a, b;
string gjsub(string x, string y)
{
int lenx = x.size(), leny = y.size();
string ans = "";
// 判断符号,保证 x >= y
if (lenx < leny)
{
ans += "-";
swap(x, y);
swap(lenx, leny);
}
else if (lenx == leny)
{
if (x < y)
{
ans += "-";
swap(x, y);
}
}
int cs = max(lenx, leny);
vector<int> a, b, sum;
for (int i = lenx - 1; i >= 0; i--)
a.push_back(x[i] - '0');
for (int i = leny - 1; i >= 0; i--)
b.push_back(y[i] - '0');
int tmp = 0, jw = 0; // jw 为借位
for (int i = 0; i < cs; i++)
{
tmp = a[i] - jw;
if (i < leny) tmp -= b[i];
if (tmp < 0)
{
jw = 1;
tmp += 10;
}
else
{
jw = 0;
}
sum.push_back(tmp);
}
// 去除前导零(但至少保留一位)
while ((int)sum.size() > 1 && sum.back() == 0)
sum.pop_back();
for (int i = sum.size() - 1; i >= 0; i--)
ans += char(sum[i] + '0');
return ans;
}
int main()
{
cin >> a >> b;
cout << gjsub(a, b);
return 0;
}
注意
- 比较两数大小时,长度不同直接比长度,长度相同用字符串字典序(C++ 的
string比较与数值字典序一致,因为都是数字字符)。 - 借位处理是关键:
tmp = a[i] - jw - (i < leny ? b[i] : 0),若小于 0 则加 10 并标记借位。 - 去前导零时,
sum是低位在前,所以末尾是最高位。
三、高精度乘法(高精 × 高精)
思路
模拟竖式乘法,使用卷积思想:
- 将两个数倒序存入
vector<int>。 - 双重循环,
sum[i+j] += a[i] * b[j](不考虑进位)。 - 统一处理进位:从低位到高位,将每一位
sum[i]的十位及以上进位到下一位。 - 去除结果末尾的前导零(高位零)。
- 倒序输出。
代码(函数模板)
cpp
#include <bits/stdc++.h>
using namespace std;
string a, b;
string gjmul(string x, string y)
{
int lenx = x.size(), leny = y.size();
int cs = lenx + leny; // 乘积最多 lenx+leny 位
vector<int> a, b, sum(cs, 0);
for (int i = lenx - 1; i >= 0; i--)
a.push_back(x[i] - '0');
for (int i = leny - 1; i >= 0; i--)
b.push_back(y[i] - '0');
// 无进位累乘
for (int i = 0; i < lenx; i++)
for (int j = 0; j < leny; j++)
sum[i + j] += a[i] * b[j];
// 统一进位
int jw = 0;
for (int i = 0; i < cs; i++)
{
int tmp = jw + sum[i];
jw = tmp / 10;
sum[i] = tmp % 10;
}
// 去除前导零(高位在末尾)
while ((int)sum.size() > 1 && sum.back() == 0)
sum.pop_back();
string ans = "";
for (int i = sum.size() - 1; i >= 0; i--)
ans += char(sum[i] + '0');
return ans;
}
int main()
{
cin >> a >> b;
cout << gjmul(a, b);
return 0;
}
注意
- 乘积位数最多为
lenx + leny,分配sum大小为lenx+leny可以保证进位不越界。 - 进位处理放在双重循环之后,更简洁,且避免反复取模。
- 去前导零时,如果结果为
0,保留一个0。
四、高精度除以低精度(高精 ÷ 低精)
思路
模拟除法竖式,从高位到低位逐位求商:
- 除数
b是long long类型(低精度)。 - 用字符串
x存储被除数,从最高位开始,维护当前余数ys。 - 每一步:
tmp = ys * 10 + 当前位数字,商位 =tmp / b,余数更新为tmp % b。 - 将所有商位存入
deque<int>,然后去除前导零(高位零)。 - 返回结构体
Number,包含商(字符串)和余数(long long)。
代码(函数模板)
cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
string a;
int b;
struct Number
{
string shang;
ll yu;
};
Number gaochudi(string x, ll y)
{
Number cur;
// 除数为 0 时返回特殊标识
if (y == 0LL)
{
cur.shang = "-1";
cur.yu = 0;
return cur;
}
int lenx = x.size();
deque<int> a, sum;
for (int i = 0; i < lenx; i++)
a.push_back(x[i] - '0');
ll ys = 0;
for (int i = 0; i < lenx; i++)
{
ll tmp = ys * 10 + a[i];
sum.push_back(tmp / y);
ys = tmp % y;
}
// 去除前导零(高位在 front)
while ((int)sum.size() > 1 && sum.front() == 0)
sum.pop_front();
string ans = "";
for (int i = 0; i < (int)sum.size(); i++)
ans += char(sum[i] + '0');
cur.shang = ans;
cur.yu = ys;
return cur;
}
int main()
{
cin >> a >> b;
Number tp = gaochudi(a, b);
cout << tp.shang << endl << tp.yu;
}
注意
- 除数为 0 时,模板返回
"-1"作为错误标识(实际使用时需注意)。 - 因为低精度除法,余数
ys不会超过y-1,用long long足够。 - 使用
deque便于从头部弹出前导零,也可以改用vector然后反转。
五、综合对比与使用建议
| 运算 | 输入类型 | 输出类型 | 核心技巧 |
|---|---|---|---|
| 加法 | 两个字符串 | 字符串 | 倒序相加,处理进位 |
| 减法 | 两个字符串 | 字符串 | 判断符号,借位处理,去前导零 |
| 乘法 | 两个字符串 | 字符串 | 卷积累乘,统一进位,去前导零 |
| 除法(高精÷低精) | 字符串 + long long | 结构体(商+余数) | 从高位模拟竖式,余数迭代 |
所有模板均以字符串作为输入输出,便于处理任意长度的大整数,且代码风格统一,易于集成。
改进扩展
- 高精 ÷ 高精 需要更复杂的试商过程,此处未提供。
- 可以增加负数支持(目前除法仅处理非负)。
- 乘法可优化为 FFT(快速傅里叶变换)以处理超长位数,但模板中的 O(n2)O(n^2)O(n2) 对于几千位以内的竞赛题已足够。
六、测试样例
「注」:觉得信不过的可以拿去测一下
加法
输入:12345678901234567890 98765432109876543210
输出:111111111011111111100
减法
输入:10000000000000000000 1
输出:9999999999999999999
乘法
输入:123456789 987654321
输出:121932631112635269
除法 (高精 ÷ 低精)
输入:1234567890123456789 12345
输出:
100005098674803
3024 (余数)
希望这份博客能帮助你快速掌握高精度计算的核心。若有疑问,欢迎留言交流!
完整代码已全部使用你的模板,可直接复制使用。