不能直接用 int 或 long long 做大数乘法,因为其位数上限远低于大数结果(如 100 位数相乘得 200 位,而 long long 仅支持约 19 位),必然溢出;应使用 vector<int> 逆序存低位,按竖式原理 res[i+j] += a[i]*b[j],再统一进位并去除前导零。

为什么不能直接用 int 或 long long 做大数乘法
因为超出类型能表示的范围就会溢出,结果完全不可信。比如两个 100 位的十进制数相乘,结果最多 200 位,而 long long 最多撑到 19 位十进制数。不是精度不够,是根本存不下。
常见错误现象:12345678901234567890 * 98765432109876543210 算出来是负数或零;或者用 std::to_string 转数字再乘,运行时直接崩溃(字符串转整数失败)。
- 别试图用
double中转——精度丢失严重,17 位以上就不可靠 - 别依赖第三方大数库(如 GMP)除非项目已强制引入——纯 C++ 场景下要自己可控
- 竖式模拟的核心是“按位存、逐位算、统一进位”,不是把字符串当数字解析
怎么用 vector<int> 存储并实现竖式乘法
把数字低位存在 vector 前端(索引 0),高位在后,这样进位时 push_back 就行,不用频繁挪动内存。比如 "123" 存成 {3, 2, 1},加减乘都对齐索引操作。
实操关键点:
立即学习“C++免费学习笔记(深入)”;
- 输入字符串先逆序转为
vector<int>:每个字符减'0',检查是否为数字 - 两数相乘时,
res[i + j]累加a[i] * b[j],这是竖式里“第 i 位 × 第 j 位影响第 i+j 位”的直接映射 - 进位必须单独遍历处理:不能边算边进,否则
res[i + j + 1]会被重复进位 - 结果 vector 可能前导零(比如乘 0),最后要从末尾往前找第一个非零位,再反转输出
示例片段(不封装函数,只看逻辑):
vector<int> a = {3, 2, 1}; // "123"
vector<int> b = {6, 5, 4}; // "456"
vector<int> res(a.size() + b.size(), 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() - 1; i++) {
res[i + 1] += res[i] / 10;
res[i] %= 10;
}
// res 此时是低位在前的 {8, 8, 0, 5, 0} → 反转去前导零 → "56088"
string 输入校验和边界情况怎么处理
用户传进来的不一定是干净正整数:可能为空、全空格、带符号、含非法字符、开头一堆 0。这些不拦住,后面数组访问直接越界或逻辑错乱。
必须做的检查:
- 用
find_first_not_of("0123456789")检查非法字符;允许开头一个'-',但本题是“列竖式”,默认非负,遇到负号直接报错或按绝对值算(需明确约定) - 去除首尾空格后,如果长度为 0 或全是
'0',直接返回"0"—— 不要让它进主循环生成一堆 0 的 vector - 输入
"0"和"123"相乘,不能让vector存{0}后还参与双层 for 循环——短路掉:任一数为 0,结果就是"0" - 不要用
stoi/stoll做任何解析——它们会截断或抛异常,且无法处理超长串
性能和可读性之间怎么取舍
纯 O(n×m) 竖式足够应付几千位以内的数;但若真要上万位,FFT 或 Karatsuba 就得上了——不过那已经不是“模拟竖式”范畴了。
当前实现的关键妥协点:
- 用
vector<int>而不是vector<char>:虽然单个数字只占 0–9,但运算中中间值可能到 81(9×9),进位后更高,int更安全,空间开销可接受 - 不预分配
res大小然后用at():用[]加resize,避免 bounds check 开销(Release 模式下差异明显) - 输出字符串时,不要用多次
+=拼接:先构造好string长度,再用索引赋值,最后reverse - 别为了“看起来简洁”把进位逻辑塞进乘法循环里——可读性和 debug 成本远大于那几行省略
最易被忽略的是:结果 vector 的 size 是 a.size() + b.size(),但最终有效位数可能只比这个少 1(比如两个最高位都是 1),所以去前导零时,一定要从最后一个索引开始倒着扫,而不是固定删一个。










