不能直接用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 ,则digit += 10且borrow = 1 - 结果字符串最后要
erase(0, result.find_first_not_of('0'))去前导零;若结果为空,说明是 0,需设为"0"
C++ 实现示例:只处理非负整数相减(最常用子场景)
这是高频面试/ACM 场景:输入两个非负 string,输出其差(允许为负)。下面代码不依赖额外库,仅用标准 string 和 vector:
#include#include #include 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; }
std::vectorzuojiankuohaophpcnintyoujiankuohaophpcn res; int i = x.size() - 1, j = y.size() - 1, borrow = 0; while (i youjiankuohaophpcn= 0) { int d1 = x[i] - '0'; int d2 = (j youjiankuohaophpcn= 0) ? y[j] - '0' : 0; int digit = d1 - d2 - borrow; if (digit zuojiankuohaophpcn 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 youjiankuohaophpcn= 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"这种情况”。











