C++如何实现大整数的加减乘除_C++高精度计算类封装教程【实战】

1次阅读

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

C++如何实现大整数的加减乘除_C++高精度计算类封装教程【实战】

为什么 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_backinsert(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 位)。实际工程中,更推荐基于已有的 subtractcompare 实现「试商」。

两种可行路径:

  • 简单版:被除数循环减除数,每减一次商加 1——仅适用于商很小的情况(如 1000 / 999),否则超时
  • 推荐版:对每一位商二分枚举 0–9,用 multiply(divisor, digit) 判断是否 ≤ 当前余数部分;需要提前写好单数字乘法和比较
  • 注意:除零必须提前检查,返回前清掉商的前导零(但商为 0 时保留一个 0)

真正难的不是算法,是把所有边界条件串起来:空输入、全零、符号处理、进位残留、容器越界访问……写完务必用 "0""1""1000000000000""999...999" 这类极端样例过一遍。

text=ZqhQzanResources