c++需手写高精度因long long上限约10¹⁸且__int128不跨平台;核心是字符串转vector(低位在前),加减乘除模拟竖式,注意进位/借位、大小比较、前导零及边界处理。

为什么 long long 不够用,又不能直接上 __int128
因为标准 C++ 没有内置大整数类型,long long 最大只能到 10¹⁸ 左右,一做乘法或阶乘就溢出;而 __int128 虽然 GCC 支持,但不跨平台(Clang/macos、MSVC 完全不认),线上 OJ 也常禁用。真要算 1000! 或两个 10⁵ 位数相乘,必须自己管存储和进位逻辑。
核心思路是:把数字当字符串读入,转成 vector<int></int> 存低位在前(比如 "123" → {3,2,1}),所有运算按小学竖式模拟。
- 加减法从下标 0 开始逐位算,维护
carry - 乘法用双层循环,
i位 ×j位结果存到i+j位,再统一进位 - 除法别硬刚长除法——先实现比较函数和减法,再用「减法逼近」或二分试商(更稳)
operator+ 和 operator- 的进位/借位陷阱
很多人写加法时只处理了 carry,忘了两数长度不同:比如 "999" + "1",短数遍历完后,carry 还得继续往高位推。减法更危险——没做大小判断就硬减,结果变负数还全是补码乱码。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 统一把输入字符串转成
vector<int></int>,低位在前,长度补零对齐 - 加法最后检查
carry是否非零,是则 push_back - 减法前先用自定义
cmp函数比大小,确保大数减小数;结果为负时单独记符号位,不塞进数字容器 - 避免在循环里频繁
push_back或insert(0, x)——前者导致多次内存重分配,后者是 O(n) 操作
乘法用 O(n²) 双循环,但别在内层实时进位
常见错误是边乘边进位,比如 a[i] * b[j] 算完立刻加到 res[i+j] 并模 10、除 10。这会导致后续 i+j+1 位置的值被错误进位两次——因为 a[i]*b[j] 的高位可能还没被其他乘积项覆盖。
正确做法是两步走:
- 第一遍:只做乘积累加,
res[i+j] += a[i] * b[j],此时res[k]可能 ≥10 - 第二遍:从低位到高位统一进位:
res[k+1] += res[k] / 10; res[k] %= 10 - 最后去掉高位多余的 0(但至少留一位,防止结果为 0 时变空)
示例片段:
for (int i = 0; i < a.size(); i++) for (int j = 0; j < b.size(); j++) res[i+j] += a[i] * b[j]; for (int i = 0; i < res.size(); i++) { if (res[i] >= 10) { res[i+1] += res[i] / 10; res[i] %= 10; } }
除法别手写长除法,用「减法循环」或「二分试商」更可靠
手写长除法容易错位、漏借、边界崩溃,尤其被除数远大于除数时(比如 10⁵ 位 ÷ 10 位)。实际工程中,更推荐基于已有的 subtract 和 compare 实现「试商」。
两种可行路径:
- 简单版:被除数循环减除数,每减一次商加 1——仅适用于商很小的情况(如
1000 / 999),否则超时 - 推荐版:对每一位商二分枚举 0–9,用
multiply(divisor, digit)判断是否 ≤ 当前余数部分;需要提前写好单数字乘法和比较 - 注意:除零必须提前检查,返回前清掉商的前导零(但商为 0 时保留一个 0)
真正难的不是算法,是把所有边界条件串起来:空输入、全零、符号处理、进位残留、容器越界访问……写完务必用 "0"、"1"、"1000000000000"、"999...999" 这类极端样例过一遍。