用 unsigned long long 计算阶乘上限为 20,21! 开始静默溢出;更大阶乘需用 std::vector 存十进制各位并模拟竖式乘法,注意进位、前导零清理及中间值溢出防护。

用 unsigned long long 算小阶乘最简单,但上限很明确
小于等于 20 的阶乘还能塞进 unsigned long long(典型 64 位系统),21! 就直接溢出——不是报错,而是静默回绕成错误值。比如 std::cout 输出的不是正确结果,而是 <code>14197454024290336768 这种明显不对的数。
实操建议:
- 如果只处理
n ≤ 20,直接用循环累乘unsigned long long,代码短、快、没副作用 - 加个输入检查:
if (n > 20) { throw std::invalid_argument("n too large for unsigned long long"); } - 别用
int或long——它们在多数平台连13!都存不下
要算大阶乘就得换存储方式,std::vector<int></int> 是最可控的选择
把数字拆成十进制各位存进 std::vector<int></int>,每次乘法手动模拟竖式计算。不依赖外部库,逻辑透明,调试方便。
关键点:
- 从低位到高位存(
digits[0]是个位),乘法时按位进位,最后再反转或倒序输出 - 每次乘完要清理前导零:
while (digits.size() > 1 && digits.back() == 0) digits.pop_back(); - 乘数不能太大——单次乘法中,若当前位是
d,乘上k后进位最多是(d * k) / 10,所以k最好不超过1000量级,避免中间溢出int
示例片段(核心乘法):
for (int i = 0; i <h3> <code>boost::multiprecision::cpp_int</code> 能省事,但得引入外部依赖</h3><p>如果你项目已用 Boost,<code>cpp_int</code> 是最省心的大整数方案:支持任意精度、重载了全部运算符、能直接和 <code>int</code> 混合运算。</p><p>但要注意:</p>
- 编译需链接
-lboost_system(部分平台),头文件是<boost></boost> - 性能比手写
vector版低约 2–3 倍(函数调用开销 + 内存管理),对1000!这种还算快,但上万位就开始明显变慢 - 它不会自动报溢出——只是默默变大;你要自己判断是否“过大”,比如监控
number.str().size()是否超预期长度
溢出检测不能只靠运行后看结果,得在乘法过程中拦截
用原生类型时,C++ 不提供乘法溢出的跨平台内置检测。靠事后检查结果变小(如 result )不可靠——因为 <code>0 * x == 0 也会触发误报。
更稳妥的做法:
- 用
std::mul_overflow(C++23):传入两个unsigned long long,返回bool并通过引用输出结果 - 降级兼容:对
a * b,先判断b != 0 && a > ULLONG_MAX / b,成立则溢出(注意除零) - 手写大数时,每次
product = digit * multiplier + carry后立刻检查product > 9——这是进位发生的信号,不是错误;真正要拦的是product超出int范围(比如 > 2e9),此时应改用long long存中间值
最易被忽略的一点:阶乘本身增长极快,1000! 有 2568 位十进制数——哪怕你解决了溢出,输出、日志、甚至字符串转换都可能成为新瓶颈。别只盯着乘法那几行代码。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











