高精度减法需模拟手算借位,用vector存低位在前的十进制位;先比较大小并统一为大减小,逐位计算并处理借位,结果去前导零但保留单个0。

高精度减法的核心逻辑:模拟手算借位
高精度减法不是直接用 long long 或 __int128 解决的——它本质是字符串/数组层面的逐位运算,关键在处理「被减数小于减数」和「连续借位」。C++ 没有内置大整数类型,必须自己维护数字序列(通常用 vector 存低位在前的十进制位)。
常见错误现象:string 直接转整数溢出、未判断大小导致结果为负但没加负号、借位后某位变成 -1 却没继续向上借。
- 先比较两数绝对值大小,决定是否加负号、是否交换操作数
- 统一按「大减小」做,结果再补符号
- 从低位(下标 0)开始遍历,用
carry记录借位(初始为 0,遇到不够减就设为 -1,并给高位传 -1) - 每位计算:当前位差 =
a[i] - b[i] - carry;若差 ,则差 += 10,carry = 1;否则carry = 0
如何安全处理前导零与空结果
减法极易产生前导零(比如 1000 - 999 = 1,中间可能存成 [1,0,0,0]),不清理会导致输出错误或后续运算异常。更隐蔽的问题是结果为 0 时,所有位都是 0,删完变空容器。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 计算完从高位(即
res.size()-1)往前找第一个非零位 - 用
while (i > 0 && res[i] == 0) i--,注意保留至少一位(i >= 0) - 截取
res.begin()到res.begin() + i + 1,生成新 vector - 如果最终只剩一个 0(即
res == {0}),必须保留它——这是唯一合法的零表示
vector 存储 vs string 存储的取舍
两种方式都可行,但行为差异明显:用 string 读入方便,但每位是 char,每次要 c - '0' 转换;用 vector 运算快,但输入需手动拆解。性能上差别不大,但易错点集中于类型混淆。
典型陷阱:
- 把
string s = "123"直接当数字用:s[0]是'1'(ASCII 49),不是1 - 用
vector存数字位,结果在运算中隐式转成 int 时出错(如'0' - '0'得 0,但'a' - '0'就乱了) - 输入含负号时,
string处理要提前剥离,而vector通常只存绝对值,符号单独记
推荐统一用 vector 存非负位数组,符号用 bool is_negative 单独管理。
完整减法函数模板的关键参数与边界
一个可用的减法函数不应只返回结果,还要能应对各种输入组合:正减正、正减负(即加法)、负减正(即加法+负号)、负减负(即绝对值相减)。但「高精度减法模板」通常指纯非负整数减法,复杂符号逻辑应由上层封装。
实操建议写两个基础函数:
-
vector:要求sub(const vector & a, const vector & b) a >= b >= 0,返回a - b的正结果 -
vector:对外接口,自动判符号、调用subtract(const string& s1, const string& s2) sub或转换为加法
注意:sub 内部不处理负数,也不检查大小——这正是模板高效的前提:责任分离。把校验和符号逻辑放在外层,内层专注运算正确性。
最容易被忽略的是:当两数完全相等时,sub 必须返回 {0},而不是空 vector 或全零 vector。这个细节在链式调用或作为其他运算输入时会暴露问题。










