阶乘 n! 到底是什么:从 0!=1 到 100! 的完整算法
讲清阶乘 n! 的定义与递推式,说明 0! 为何等于 1,演示 5! 与 10! 的真实算例,解释它增长有多快,以及在排列组合与概率里怎么用,还有大数怎么精确算。
阶乘 n! 到底是什么:从 0!=1 到 100! 的完整算法
阶乘是中学就见过的符号,一个数字后面跟个感叹号,但真要说清它的定义、为什么 0! 等于 1、它增长有多吓人,很多人会卡住。这篇就把这几件事讲透,顺便给出几个能自己手算核对的例子。
阶乘的定义和那条递推式
非负整数 n 的阶乘记作 n!,意思是把 1 到 n 之间的每个整数连乘起来。写成式子就是:
n! = 1 × 2 × 3 × … × n
所以 3! = 1 × 2 × 3 = 6,4! = 1 × 2 × 3 × 4 = 24。还有一条更重要的递推式:
n! = n × (n−1)!
这条式子说的是,每个阶乘都能由前一个推出来。5! 就是 5 乘以 4!,也就是 5 × 24 = 120。这个递推关系不只是方便计算,它还是理解 0! 的关键。
为什么 0! = 1
很多人第一次看到 0! = 1 会觉得别扭,空的乘积怎么会是 1 而不是 0。这不是随便定的,有两个角度能讲明白。
第一个角度是排列。阶乘数的是把 n 个物品排成一排有多少种方法。3 个物品有 6 种排法,正好是 3!。那零个物品呢,恰好只有一种排法,就是什么都不放的空排法,所以 0! = 1。
第二个角度是让递推式自洽。把 n = 1 代进 n! = n × (n−1)!,得到 1! = 1 × 0!。已知 1! = 1,那 0! 就必须等于 1,否则整条递推链都断了。组合数学里 C(n,0) = 1 这类公式,也靠 0! = 1 才算得对。
它增长有多快
阶乘的增长速度非常吓人,比指数还猛。来看一串真实数字:
- 5! = 120
- 10! = 3628800
- 13! = 6227020800
- 21! = 51090942171709440000
注意 21! 这个数。JavaScript 里普通数字只在 2 的 53 次方以内保持精确,而 21! 已经越过这条线,所以基于普通浮点数的计算器从 21! 起尾数就开始出错,只是它不会告诉你。等算到 100!,正确答案是一个 158 位的整数,以 933262154439441526 开头,结尾整整 24 个零,普通工具只会给你一个四舍五入的 9.33e157。
尾随零的个数其实有公式,叫勒让德公式:floor(n/5) + floor(n/25) + floor(n/125) + …。对 100! 就是 floor(100/5) + floor(100/25) = 20 + 4 = 24,和上面说的 24 个零对上了。一个尾随零来自因子 10 = 2 × 5,而 n! 里因子 2 总比因子 5 多,所以只数 5 就够。
阶乘用在哪
阶乘最常出现的地方是排列和组合。从 n 个里取 r 个排队,方法数是排列数:
P(n,r) = n! / (n−r)!
如果只关心取哪几个、不关心顺序,那是组合数:
C(n,r) = n! / (r! × (n−r)!)
举个具体的。双色球从 33 个红球里选 6 个,中奖组合数就是 C(33,6) = 33! / (6! × 27!) = 1107568。概率题里也到处是阶乘,比如生日悖论、扑克手牌、洗牌结果,底层都是把若干阶乘代进上面两条公式。需要现成的排列组合结果时,可以直接用 组合排列计算器,省去手动展开阶乘的步骤。
我自己怎么核对面试答案
我之前写过一个递归阶乘函数,提交前总想拿个精确参考对一下。最容易翻车的就是大数那一段。我习惯把同一个 n 输进 阶乘计算器,读出完整的 BigInt 结果,再和自己的输出逐位比。有一次我的函数算到 25! 就开始尾数对不上,正是普通数字溢出导致的,要不是拿精确值对照,这个 bug 很可能就混进去了。所以我现在的习惯是,凡是涉及大阶乘的代码,先用精确值兜个底再说。
要注意双阶乘 n!! 和 (n!)! 是两回事。双阶乘是每隔一个数连乘,8!! = 8 × 6 × 4 × 2 = 384,7!! = 7 × 5 × 3 × 1 = 105;而 (7!)! 是 5040 的阶乘,大得离谱。还有,普通阶乘只对非负整数有定义,−3 或 2.5 这种输入没有值,那要靠伽马函数才行。
阶乘看着简单,真正用起来对精度和量级的要求都不低。把定义、递推式和那条尾零公式握在手里,再配上一个能精确算大数的工具,排列组合和概率题就好对付多了。
Made by Toolora · Updated 2026-06-13