因为long long仅支持约10¹⁸量级,超限会静默溢出;c++无内置大整数,需字符串模拟手算,核心是低位对齐、进位处理与符号统一。

为什么不能直接用 long long 做大整数运算?
因为 long long 最多表示约 10¹⁸ 量级的数,一旦超过(比如 100 位十进制数),就会溢出,结果完全不可信。C++ 标准库不提供内置 bigint 类,必须自己实现或依赖第三方(如 Boost.Multiprecision),但自定义能帮你真正理解进位、借位、符号处理这些底层逻辑。
- 溢出后不会报错,而是静默回绕,
a + b可能变成负数甚至 0 - 输入来自字符串时,
std::stoll直接抛std::out_of_range异常 - 即使只做加法,也要考虑正负号组合:正+负 实际是减法,负+负 要转为加法再加负号
如何用字符串存数字并实现加法?
核心是模拟手算:从低位对齐、逐位相加、维护进位。关键不是“怎么写循环”,而是“怎么对齐”和“怎么处理符号”。
- 字符串存储用
std::string,低位在尾(如"123"存为'1','2','3',个位是[2]) - 先统一符号:若两数异号,转为减法(调用
subtract),同号则按绝对值相加再补符号 - 对齐操作别用
insert(0, "0"),会频繁内存移动;改用双指针从末尾倒着扫,索引 =s.size() - 1 - i - 进位变量用
int carry = 0,每次加完更新:carry = sum / 10,当前位 =sum % 10
// 示例:add("999", "1")
// i=0 → '9'+'1'+0 = 10 → digit=0, carry=1
// i=1 → '9'+'0'+1 = 10 → digit=0, carry=1
// i=2 → '9'+'0'+1 = 10 → digit=0, carry=1
// 结束后 carry=1 → 补 '1' → "1000"
减法最容易错在哪几个地方?
不是借位逻辑难,而是边界和符号处理一错就全崩:
- 被减数小于减数时,结果应为负的(
subtract("5", "10")→"-5"),但很多人直接返回空或报错 - 借位时,遇到 0 要连续向前找非零位,比如
"1000" - "1":个位 0-1 不够,向十位借 → 十位是 0,继续向百位借 → 百位也是 0,最终千位 1 变成 0,百位得 10,再逐层拆解 - 前导零必须清理,
"00123"得压成"123",但结果为"0"时要保留一个零 - 字符串比较大小不能用
>直接比(字典序),得先比长度,等长再用std::string::compare
乘法性能差的根源和简单优化点
朴素 O(n²) 乘法在 10⁴ 位以上就会明显卡顿,但初版不必上 FFT:
立即学习“C++免费学习笔记(深入)”;
- 别用嵌套 for 把结果存在二维数组里再累加,直接用一维
std::vector<int></int>存中间结果,索引i+j对应十进制第i+j位 - 每次乘完立刻处理进位,避免最后集中模 10,否则中间值可能超
int - 如果其中一个数很小(比如
multiply(big, "123")),优先走「小数遍历」分支,把大数当被乘数,小数当乘数,减少外层循环次数 - 输出前仍要清前导零,且注意结果可能全零 → 留一个
'0'
真正麻烦的不是单个运算,而是符号、空字符串、全零输入、最大最小边界这些 case 怎么兜住。写完加法后,先拿 add("0", "0")、add("-0", "5")、add("999999999999999999999", "1") 这几组快速过一遍,比写一百行注释更管用。










