贝利信息

c++中如何计算阶乘_c++递归与循环实现阶乘的方法【详解】

日期:2026-01-16 00:00 / 作者:冰火之心
递归实现阶乘的栈溢出风险在于调用深度等于n,每层递归需压入返回地址、局部变量等,当n超过几百(如1000)时易耗尽默认1–8MB栈空间,引发Segmentation fault或stack overflow。

递归实现阶乘时栈溢出风险在哪

递归写 factorial(n) 看似简洁,但实际调用深度等于 n。当 n 超过几百(比如 n = 1000),多数编译器默认栈空间(通常 1–8 MB)就会被压垮,触发 Segmentation faultstack overflow 异常。

关键不是“能不能算”,而是“谁来承担调用开销”。每层递归都得压入返回地址、局部变量、寄存器备份——这些加起来远超一个 int 占用。

循环实现阶乘要注意整数溢出

for 循环算阶乘更可控,但 intlong long 很快就爆掉:13! = 6227020800 已超出 int(通常 32 位),21! 就超过 long long(64 位)最大值 9223372036854775807

这意味着:即使你写对了循环逻辑,结果也大概率是错的——而且不会报错,只会静默溢出(未定义行为)。

模板 + constexpr 实现编译期阶乘

如果参数是字面量且不大(比如用于数组长度、模板参数),用 constexpr 递归模板能彻底避免运行时开销,并在编译时报错溢出。

template
constexpr unsigned long long factorial() {
    static_assert(N < 21, "N too large for constexpr factorial");
    return (N <= 1) ? 1 : N * factorial();
}

调用如 constexpr auto f5 = factorial();,编译器直接替换为 120;若写 factorial(),编译失败并提示 static_assert 错误。

什么时候该用第三

方大数库

当需求明确要支持 n > 20 且结果需精确(比如密码学、组合数学验证),硬编码 unsigned long long 就是自欺欺人。此时应切换到真正能处理任意精度的方案。

最轻量的选择是 boost::multiprecision::cpp_int,它头文件即用,无链接依赖:

#include 
using namespace boost::multiprecision;

cpp_int factorial(int n) { cpp_int result = 1; for (int i = 2; i <= n; ++i) result *= i; return result; }

真正麻烦的从来不是“怎么写阶乘”,而是想清楚:你要的是编译期常量、运行时小值快速计算,还是任意精度下的正确性——选错路径,后面全是补丁。