大数减法不能直接用int或long long,因其位宽有限会导致溢出和静默截断;须手动模拟竖式减法,逐位计算并处理借位,用string或vector存储;还需先比较两数大小以确定结果符号。

大数减法为什么不能直接用 int 或 long long
因为 C++ 原生整型有固定位宽,int 通常最多存约 21 亿,long long 最多约 9×10¹⁸。一旦数字超过这个范围(比如 100 位十进制数),直接相减会溢出或得到错误结果——不是报错,而是静默截断,结果完全不可信。
所以必须手动模拟竖式减法:从低位到高位逐位计算,维护借位(borrow),并用容器(如 string 或 vector<int></int>)存每一位数字。
如何处理负号和大小比较
减法本质是 a - b,但若 a ,结果为负。不能靠最终符号位反推,得先比较两数绝对值大小,再决定是否交换并标记负号。
- 去掉输入字符串的前导零(但保留单个
"0") - 先比长度:长的数更大;等长时字典序比较(
"123" > "99") - 若
a ,实际计算 <code>b - a,然后在结果前加"-"
注意:比较必须基于去零后的字符串,否则 "00123" 和 "123" 会被误判。
逐位减法 + 借位的实现细节
从最低位(字符串末尾)开始遍历,用 int 存当前位差:digit_a - digit_b - borrow。若结果为负,需加 10 并设下一位 borrow = 1;否则 borrow = 0。
关键点:
- 索引要从右往左对齐:
i = a.size()-1-k,j = b.size()-1-k,k 从 0 开始递增 - 某数已遍历完时,对应位按
0处理(不要越界访问) - 最后可能剩一个借位(如
"100" - "99"),但只要 a ≥ b 就不会出现;若 a - 结果数组高位可能有前导零(如
"1000" - "999" = "0001"),最后要从第一个非零位开始截取,全零则返回"0"
示例核心逻辑片段:
string subtract(string a, string b) {
bool neg = false;
if (compare(a, b) = 0 || j >= 0) {
int d1 = i >= 0 ? a[i--] - '0' : 0;
int d2 = j >= 0 ? b[j--] - '0' : 0;
int diff = d1 - d2 - borrow;
if (diff <h3>容易漏掉的边界情况</h3><p>实际写的时候,最常翻车的是这几个:</p>
- 输入含负号:函数应只处理非负大数,调用前剥离
"-"并统一转换为a - b形式 - 全零输入:
"0"、"000"、"-0"都要归一化为"0" - 借位贯穿全程:
"1000" - "1"要连续借位三次,不能只借一次就停 - 结果为 0:去零后变成空串,必须显式设为
"0",否则返回空字符串 - 传入空字符串:应提前检查并返回错误或抛异常,而不是崩溃
真正难的不是算法本身,而是把所有这些“看起来 trivial”的边界兜住——尤其是前导零处理和符号统一,稍有疏忽就会在某个测试用例上挂掉。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











