推荐用 std::vector 存低位到高位的数字位,避免字符串模拟;用 int 实现万进制提升性能;符号单独用 bool 管理;加法就地修改并清理前导零;乘法用朴素 O(n²);除法模拟手算试商;边界需重点测试。

用 std::vector<int></int> 存低位到高位,别用字符串模拟
字符串模拟大整数看似直观,但每次加减都要遍历字符、处理 ASCII 偏移、进位逻辑夹在 '0' 和 int 之间,容易出错且慢。直接用 std::vector<int></int> 存数字的每一位(digits[0] 是个位),进位就是整除和取模,逻辑干净。
- 每位存 0–9 最安全,但牺牲性能;更常用的是存 0–9999,用
int当“万进制”单元,减少循环次数 - 构造函数里要跳过前导零,否则
size()失真,operator==会误判 - 负号单独用
bool sign管理,别把负数塞进 vector —— 否则减法要额外处理补码或符号逻辑
operator+= 必须就地修改,避免无谓拷贝
实现加法时,如果写成 BigNum operator+(const BigNum& a, const BigNum& b) { return a += b; },那 operator+= 就得是核心。它必须修改左操作数,不能新建 vector 再 swap —— 那样每次加法都触发内存分配,O(n) 变成 O(n) + 分配开销。
- 先按位累加,用
int carry = 0记进位,每位计算:sum = digits[i] + other.digits[i] + carry - 超出当前长度时,用
push_back()扩容,别提前resize()—— 容易多占内存 - 加完后检查最高位是否为 0(比如 999+1=1000,但若没清空末尾 0 可能剩
{0,0,0,1}),要从末尾pop_back()直到digits.back() != 0或只剩一位
乘法用朴素 O(n²),别一上来就上 FFT
除非你明确处理几万位整数,否则 FFT / Karatsuba 的常数开销远大于收益,还引入浮点误差或模运算复杂度。对千位以内整数,双层 for 循环最稳。
- 结果最大长度是
a.size() + b.size(),初始化res为全 0 的 vector,长度取这个上限 - 内层循环:
res[i + j] += a.digits[i] * b.digits[j],注意是i+j不是i*j - 一轮乘完再统一进位:从
res[0]开始,carry = res[k] / base,res[k] %= base,res[k+1] += carry - 最后仍要清前导零 —— 乘 0 时整个 vector 可能全是 0,得保留一个
0
除法用「试商 + 减法」,不是移位+异或
C++ 没有内置大整数除法支持,也不能靠 / 和 % 偷懒。标准做法是模拟手算:对被除数从高位开始,每次取足够长的前缀,试一个商 digit(通常 1–9),用乘法验证是否超限,再做减法。
立即学习“C++免费学习笔记(深入)”;
- 别逐位试:用二分找当前位商,范围是
[0, base),最多 4 次比较(base=10000 时) - 关键子过程是
compare(const BigNum& a, const BigNum& b):先比长度,等长再从高位往低位比 —— 注意 vector 是低位在前,所以要反向遍历 - 减法必须要求被减数 ≥ 减数,否则先比较再调用;除零要抛异常或返回特殊值,
if (divisor.isZero()) throw std::runtime_error("division by zero")
真正难的不是算法本身,而是边界:全零输入、最小负数(-2¹⁰⁰⁰)、除法中商为 0 但余数非零、进位链贯穿整个 vector……这些地方不打日志、不写单元测试,光靠肉眼检查根本防不住。










