不能直接用 long long 做大数乘法,因其最大值约 9e18,两个 10 位数相乘即可能溢出;C++ 无内置高精度类型,需模拟竖式乘法,核心是确保每步计算不溢出,常用 vector 反向存低位,逐位相乘、统一进位。

为什么不能直接用 long long 做大数乘法
因为超过 2^63-1(约 9e18)就溢出,两个 10 位数相乘就可能越界。比如 1234567890 * 9876543210 结果是 12 位,long long 存不下。C++ 没有内置高精度类型,必须自己模拟竖式乘法过程。
关键不是“怎么存大数”,而是“怎么让每一步计算不溢出”。所以通常用 vector<int></int> 存低位在前的数字(如 "123" 存为 {3,2,1}),每位只存 0–9,乘法时逐位算、进位拆解到高位。
- 输入字符串转为反向
vector<int></int>:避免后续反转,也方便下标对齐 - 结果数组长度最多是两数长度之和(比如 100 位 × 100 位 → 最多 200 位)
- 每次
i位 ×j位,结果加到i + j位置,进位统一最后处理,比边算边进位更稳
multiply 函数的核心循环逻辑怎么写
假设 a 和 b 是反向存储的数字(a[0] 是个位),结果存在 res 中,长度预设为 a.size() + b.size():
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];
res[i + j + 1] += res[i + j] / 10;
res[i + j] %= 10;
}
}注意:这里用了「即时进位」,比全算完再进位更省内存,但要小心 res[i+j+1] 越界——所以 res 长度必须够。另外,a[i] * b[j] 最大是 81,加上之前累加值,res[i+j] 短期内不会超 int 上限,安全。
立即学习“C++免费学习笔记(深入)”;
- 不要用
string拼接中间结果,性能差且易错 - 如果想省一点空间,可以用
short存单个数字(0–9),但乘积要先转int算,否则9*9就溢出 - 循环顺序不影响正确性,但
i外层、j内层更符合直觉(固定被乘数位,遍历乘数位)
如何处理前导零和空字符串边界
输入可能是 "0"、"000" 或空串,输出不能是 "000" 或空。最简单办法是:算完后从高位(即 res 尾部)往前跳零,直到遇到非零或只剩一位。
但要注意:如果整个结果就是 0,比如 "0" * "123",所有位都是 0,必须保留一个 0。
- 转换输入时,先
erase掉开头空格和前导零,但空串要留成"0" - 反向存的时候,空字符串对应空
vector,得提前判空返回"0" - 结果转字符串时,用
while (pos > 0 && res[pos] == 0) pos--;找到最后非零位,然后倒着读到下标 0
完整代码里最容易漏掉的细节
很多人写了核心循环就以为完事了,结果 "123" * "45" 输出 "5535"(少一位)或者 "005535"(没去前导零)。真正卡住的点往往在三处:
- 输入字符串为空或全零时没单独处理,导致
vector为空,后续循环不执行,res全 0 但没截断 - 结果数组预留长度是
a.size() + b.size(),但最终有效位可能只有a.size() + b.size() - 1,高位可能为 0,必须 trim - 负号没考虑——题目虽没提,但实际使用中如果要支持负数,只需提前记录符号、转正数计算、最后加
'-',别在数字数组里塞负号
高精度乘法的复杂点不在算法本身,而在于边界控制和数据流向的确定性。哪怕只错一个下标(比如把 i+j+1 写成 i+j),整串结果就全乱。动手前先拿 "12" * "34" 在纸上跑一遍竖式,对齐下标,比调十分钟编译器更省时间。


















