大数阶乘需用std::vector存低位在前的十进制各位,核心是正确处理进位(用long long)、循环覆盖原长度并持续push_back新位,最后倒序输出;避免浮点近似、bitset模拟或错误reverse。

大数阶乘在 C++ 里不能用 long long 或 __int128
超过 20! 就会溢出 long long(约 9×10¹⁸),而 100! 有 158 位——必须自己存数字。C++ 标准库不提供大整数类型,std::vector<int></int> 或 std::string 是最直接的载体。
常见错误是试图用浮点(double)近似:结果连末尾几位都错,且无法取模或精确输出;还有人用 std::bitset 模拟,但乘法实现复杂、易越界。
- 推荐用
std::vector<int></int>存低位在前的十进制各位(如 123 →{3,2,1}) - 每次乘一个整数时,从低位到高位逐位计算进位,动态 push_back 新位
- 避免用
std::vector<char></char>存单个数字——类型窄但易混淆,且无符号溢出难调试
手写大数乘法:核心是模拟竖式,别漏进位
阶乘本质是连续乘法:fact = fact * i,所以重点是实现 multiply(vector<int>& num, int x)</int>。关键不是“怎么乘”,而是“进位怎么传、边界怎么扩”。
典型翻车点:循环只遍历原长度,忘了最高位可能产生新进位(比如 999 × 2 = 1998,多出一位);或者进位变量用 int 但乘数很大(如 10000 × 9999),导致中间值超 int 范围。
立即学习“C++免费学习笔记(深入)”;
- 进位变量必须用
long long(哪怕x是int,因为digit * x + carry可能超 2e9) - 循环结束后,只要
carry > 0,就得持续push_back(carry % 10)并更新carry /= 10 - 不要 reverse 容器来“对齐”——保持低位在前,最后输出时倒着遍历即可
void multiply(std::vector<int>& digits, int x) {
long long carry = 0;
for (int i = 0; i < digits.size() || carry; ++i) {
if (i == digits.size()) digits.push_back(0);
long long val = (long long)digits[i] * x + carry;
digits[i] = val % 10;
carry = val / 10;
}
}
输出和性能:别在循环里转字符串,也别用 std::endl
算完后要打印,有人每算一步就 std::to_string() 拼接,或用 std::ostringstream 累积——这在算 10000! 时会严重拖慢(频繁内存分配)。另外,std::endl 强制 flush,比 "\n" 慢几倍。
使用场景差异明显:如果只要结果长度,不用存全量数字(比如求 10⁶! 的位数),可用斯特林公式近似;但如果要精确值或取模,就必须完整计算。
- 输出时直接从
digits.size()-1往下遍历,用putchar或std::cout << (char)('0' + d) - 需要取模(如
% 1000000007)?那就不能存各位,改用long long滚动取模——但注意:阶乘取模 ≠ 各步取模后再乘,只要中间不溢出,是可以的 - 算 10⁵! 以上时,vector 分配和拷贝开销明显,可预估位数(log₁₀(n!) ≈ n log₁₀(n/e) + log₁₀(√2πn))reserve 空间
替代方案:什么时候该换库,而不是硬写
如果你只是临时算几个大阶乘,或者项目允许依赖,boost::multiprecision::cpp_int 是最省心的选择——支持运算符重载、自动管理内存,且底层优化过乘法(Toom-Cook 等)。
但要注意:Boost 头文件巨长,编译慢;静态链接后二进制体积增加明显;某些嵌入式或竞赛环境禁用外部库。硬写的好处是逻辑透明、无依赖、可控性强(比如你只想输出某几位,或边算边写磁盘)。
- 确认环境是否允许:检查编译器版本(
cpp_int需 C++11+)、是否有 Boost 安装路径 - 别混用:不要一半用
vector<int>,一半想调cpp_int::to_string()—— 类型割裂反而更难 debug - 竞赛中禁止 Boost?那必须手写;但公司内部工具脚本,优先选
cpp_int,少踩内存和进位坑
大数阶乘真正麻烦的从来不是“怎么乘”,而是进位变量类型选错、循环边界没兜住、输出时顺序搞反——这些地方一错,结果就全偏了,还很难定位。










