0

0

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

冰火之心

冰火之心

发布时间:2026-01-16 17:22:04

|

617人浏览过

|

来源于php中文网

原创

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

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

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

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

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

  • 不建议在生产代码中对未知大小的 n 使用纯递归
  • 若必须用递归,应加守卫: if (n > 1000) throw std::runtime_error("n too large for recursion");
  • 尾递归优化(如 GCC 的 -O2)对简单阶乘无效,因为 return n * factorial(n-1) 不是尾调用(乘法在 return 前)

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

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

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

立即学习C++免费学习笔记(深入)”;

  • 务必根据预期输入范围选类型:小值用 unsigned long long,大值必须上 boost::multiprecision::cpp_int 或自己实现大数
  • 可在循环中加入溢出检测,例如用 __builtin_mul_overflow(GCC/Clang)或手动比较:if (result > ULLONG_MAX / i) throw std::overflow_error("factorial overflow");
  • 0!1! 必须显式处理为 1,否则循环从 i=2 开始时会漏掉

模板 + constexpr 实现编译期阶乘

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

Smart Picture
Smart Picture

Smart Picture 智能高效的图片处理工具

下载
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 错误。

  • 不能用于运行时变量:int n; std::cin >> n; factorial(); 是非法的
  • static_assert 检查的是模板实例化时的 N,不是运行时值,所以安全可靠
  • 比宏更类型安全,比普通函数更早暴露问题

什么时候该用第三方大数库

当需求明确要支持 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; }

  • 不要试图自己手写“字符串模拟乘法”——边界多、易错、维护成本高
  • 注意 cpp_int 运算比原生类型慢几个数量级,只在必要时启用
  • 若项目已用 C++23,可关注 和未来可能的 std::bigint(尚未标准化)

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

相关专题

更多
java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1465

2023.10.24

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

738

2023.08.22

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

256

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

208

2023.09.04

java基础知识汇总
java基础知识汇总

java基础知识有Java的历史和特点、Java的开发环境、Java的基本数据类型、变量和常量、运算符和表达式、控制语句、数组和字符串等等知识点。想要知道更多关于java基础知识的朋友,请阅读本专题下面的的有关文章,欢迎大家来php中文网学习。

1465

2023.10.24

字符串介绍
字符串介绍

字符串是一种数据类型,它可以是任何文本,包括字母、数字、符号等。字符串可以由不同的字符组成,例如空格、标点符号、数字等。在编程中,字符串通常用引号括起来,如单引号、双引号或反引号。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

619

2023.11.24

java读取文件转成字符串的方法
java读取文件转成字符串的方法

Java8引入了新的文件I/O API,使用java.nio.file.Files类读取文件内容更加方便。对于较旧版本的Java,可以使用java.io.FileReader和java.io.BufferedReader来读取文件。在这些方法中,你需要将文件路径替换为你的实际文件路径,并且可能需要处理可能的IOException异常。想了解更多java的相关内容,可以阅读本专题下面的文章。

550

2024.03.22

php中定义字符串的方式
php中定义字符串的方式

php中定义字符串的方式:单引号;双引号;heredoc语法等等。想了解更多字符串的相关内容,可以阅读本专题下面的文章。

545

2024.04.29

高德地图升级方法汇总
高德地图升级方法汇总

本专题整合了高德地图升级相关教程,阅读专题下面的文章了解更多详细内容。

2

2026.01.16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 1.2万人学习

Rust 教程
Rust 教程

共28课时 | 4.4万人学习

Git 教程
Git 教程

共21课时 | 2.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号