不能直接用int或long long做大数减法,因其位宽固定(int约21亿,long long约9×10¹⁸),无法表示百位级大数;必须用字符串模拟手算减法,关键在符号处理、对齐、借位和前导零。

为什么不能直接用 int 或 long long 做大数减法
因为 C++ 原生整型有固定位宽:int 通常最多存 231−1(约 21 亿),long long 也只到 263−1(约 9×1018)。一旦输入是 100 位的十进制数,比如 "123456789012345678901234567890",任何内置类型都会溢出或截断——必须用字符串存数字,逐位模拟手算减法。
字符串模拟减法的核心步骤与边界处理
关键不是“写个循环”,而是处理好符号、对齐、借位和前导零。真实编码中最容易错的是:没统一正负号逻辑、借位后忘记把当前位补 10、结果全零时返回空串。
- 先判断两数符号:同号转为绝对值相减(注意谁大谁小),异号转为绝对值相加
- 用
string存非负整数时,高位在前(如"123"表示一百二十三),所以要从末尾开始遍历 - 必须保证被减数 ≥ 减数(绝对值意义下);否则交换并标记结果为负
- 每轮计算:
digit = a[i] - b[i] - borrow,若digit ,则 <code>digit += 10且borrow = 1 - 结果字符串最后要
erase(0, result.find_first_not_of('0'))去前导零;若结果为空,说明是 0,需设为"0"
C++ 实现示例:只处理非负整数相减(最常用子场景)
这是高频面试/ACM 场景:输入两个非负 string,输出其差(允许为负)。下面代码不依赖额外库,仅用标准 string 和 vector:
#include <string>
#include <algorithm>
#include <vector>
<p>std::string subtract(const std::string& a, const std::string& b) {
// 先判断大小,确保 a >= b(绝对值),否则结果加负号
bool negative = false;
std::string x = a, y = b;
if (x.length() < y.length() || (x.length() == y.length() && x < y)) {
std::swap(x, y);
negative = true;
}</p><pre class='brush:php;toolbar:false;'>std::vector<int> res;
int i = x.size() - 1, j = y.size() - 1, borrow = 0;
while (i >= 0) {
int d1 = x[i] - '0';
int d2 = (j >= 0) ? y[j] - '0' : 0;
int digit = d1 - d2 - borrow;
if (digit < 0) {
digit += 10;
borrow = 1;
} else {
borrow = 0;
}
res.push_back(digit);
i--; j--;
}
// 去前导零:从高位(即 res.back())开始找第一个非零
std::string ans;
bool leading = true;
for (int k = res.size() - 1; k >= 0; k--) {
if (leading && res[k] == 0) continue;
leading = false;
ans += ('0' + res[k]);
}
if (ans.empty()) ans = "0";
if (negative) ans = "-" + ans;
return ans;}
立即学习“C++免费学习笔记(深入)”;
容易被忽略的细节:输入含符号、前导零、空串怎么办
实际输入往往不干净。比如 "-00123"、"000"、"" 都可能进来。生产级代码必须预处理:
- 用
std::regex或手动跳过前导空格和'+'/'-',记录符号位 - 去除所有前导零后,若字符串变空或只剩一个
'0',应归一化为"0" - 如果输入是
"0"和"0",结果必须是"0",不是空串或"-0" - 借位变量
borrow必须初始化为 0,且在每位计算后显式更新,不可依赖隐式作用域
高精度减法真正难的不是算法,是把所有边界条件塞进同一套逻辑里跑通。多数人卡在“以为自己处理了负数,其实漏了 "0 - 123" 这种情况”。











