高精度减法 vs 加法
和高精度加法一样,用字符串存数字、数组模拟竖式。区别就两个:进位变借位,结果可能是负数。
思路拆解
- 读入两个字符串
- 判断符号:如果被减数小于减数,交换并标记结果为负
- 反转字符串(个位对齐下标 0)
- 字符转数字
- 逐位相减 + 处理借位(不够减就向高位借 1)
- 去前导零
- 反转输出(负号在前)
完整代码(带注释)
#include <bits/stdc++.h>
using namespace std;
string a, b;
int main() {
cin >> a >> b;
// 1. 判断符号:保证 a >= b
char flag = '+';
if (a.size() < b.size() || (a.size() == b.size() && a < b)) {
swap(a, b);
flag = '-'; // 记下来,输出时用
}
// 2. 如果相等,直接输出 0
if (a == b) {
cout << '0';
return 0;
}
int MaxLen = a.size();
vector<int> a1(MaxLen + 1, 0); // 被减数
vector<int> a2(MaxLen + 1, 0); // 减数
vector<int> a3(MaxLen + 1, 0); // 结果
reverse(a.begin(), a.end());
reverse(b.begin(), b.end());
// 3. 字符转数字
for (int i = 0; i < a.size(); i++) a1[i] = a[i] - '0';
for (int i = 0; i < b.size(); i++) a2[i] = b[i] - '0';
// 4. 逐位相减 + 借位
for (int i = 0; i < MaxLen; i++) {
if (a1[i] < a2[i]) {
a1[i] += 10; // 向高位借 10
a1[i + 1] -= 1; // 高位减 1
}
a3[i] = a1[i] - a2[i];
}
// 5. 去前导零
int index = 0;
for (int i = MaxLen; i >= 0; i--) {
if (a3[i] != 0) {
index = i;
break;
}
}
a3.resize(index + 1);
// 6. 反转输出
reverse(a3.begin(), a3.end());
if (flag == '-') cout << '-';
for (int i = 0; i < a3.size(); i++) {
cout << a3[i];
}
return 0;
}
运行示例
输入:
1000
1
输出:
999
输入:
3
5
输出:
-2
常见踩坑指南
🔴 坑 1:忘记负号
减法可能出现负数。比如算 3 - 5:
// ✅ 正确 —— 交换前先判断,记下符号
char flag = '+';
if (a.size() < b.size() || (a.size() == b.size() && a < b)) {
swap(a, b);
flag = '-';
}
// 输出时
if (flag == '-') cout << '-';
如果不处理,算完输出就少个负号,整个答案都错。
🟡 坑 2:借位后高位变负数
比如 1000 - 1,借位一路滚下去:
a1[0] = 0 < 1 → 向 a1[1] 借位
a1[1] 从 0 变成 -1
a1[1] = -1 < 0 → 又触发借位,向 a1[2] 借
a1[2] 从 0 变成 -1
...
负数会触发下一轮继续借,直到碰到不为 0 的高位为止。这套逻辑能跑通,但写的时候就靠”负数当跳板”,比较隐晦。
更清晰的写法是用借位标记:
int t = 0; // 借位标记
for (int i = 0; i < MaxLen; i++) {
a3[i] = a1[i] - a2[i] - t;
if (a3[i] < 0) {
a3[i] += 10;
t = 1;
} else {
t = 0;
}
}
两种都能过题,看你喜欢哪个风格。
🟡 坑 3:前导零清不干净
减法结果可能有好几位前导零,比如 1001 - 1000 = 1,运算完数组是 [1, 0, 0, 0],需要从高位往下扫找到第一个非零位:
int index = 0;
for (int i = MaxLen; i >= 0; i--) {
if (a3[i] != 0) {
index = i;
break;
}
}
a3.resize(index + 1); // 只保留有效位
加法和减法对照
| 加法 | 减法 | |
|---|---|---|
| 判断符号 | 不需要 | ✅ 大小判断 + 交换 |
| 核心运算 | a3[i] = a1[i] + a2[i] | a3[i] = a1[i] - a2[i] |
| 进位/借位 | >= 10 向前进 | < 0 向前借 |
| 去前导零 | if 最多查 1 位 | while 可能多位 |
| 反转输出 | 一样 | 多一个 - 号 |
总结
高精度减法的核心就一句话:
保证大减小 → 借位 → 去零 → 反转 → 别忘负号