使用方法
- 在「n(元素总数)」里填你手里的元素个数,示例填 10。允许 0 ~ 1000 的整数。
- 在「r(有序取出个数)」里填要取出并排序的个数,示例填 3。它可以等于 0,也可以等于 n,但不能大于 n。
- 点「计算」,或在任意输入框里按 Enter,结果区立刻给出 A(10,3) = 720,同时标出这个数的位数是 3 位、是否落在双精度安全区内。
- 想看「多取一个会翻多少倍」,点「加载更多」展开对照表,或直接改 r —— 表格里 r=2 是 90,r=3 是 720,r=4 是 5040,正好是 8 倍关系。
- 要拿去和「不区分顺序」的选法比,把同一组 n、r 的 C(n,r) 列一起看:示例里 C(10,3) = 120,正好是 720 除以 3! = 6。
这个排列计算器能解决什么问题
「从 n 个人里选 r 个」这句话在现实里其实有两种意思,而这两种意思的答案相差 r! 倍,这就是排列计算器存在的全部理由。
第一种是不区分顺序的:8 个人里挑 3 个人组队,先选谁后选谁不影响结果,答案是 C(8,3) = 56 种。第二种是区分顺序的:同样 8 个人选 3 个来颁发金、银、铜牌,先谁站上领奖台就是不同的结果,答案是 A(8,3) = 336 种。336 ÷ 56 = 6,正好是 3!。搞混这两个数,报名系统的名额统计、抽奖的排列组合、密码强度估算都会整体偏差一个量级。
本页具体处理四类问题:一是给定 n 与 r 得出有序选法的确切值;二是给出这个值的十进制位数,方便判断它能不能塞进数据库的整型列或前端安全整数;三是明确告诉你什么时候结果已经超出 double 能精确表示的范围,并自动换成 BigInt 算到底;四是把同 n 下逐档递增的 r 排成一张表,让你看出「多一个位置等于乘一个 (n−r+1)」这个规律,而不是每次重新算。整个排列计算器不含任何随机数,同样的输入永远得到同样的输出。
本页只算有序选法。如果你要求的是「选出来就行、不管谁在第几位」,那是组合,请用页面底部的组合计算器;如果你要的是 n! 本身这个数,则是阶乘,用阶乘计算器。本页在结果区会并排显示 C(n,r) 作为对照,但主结果永远是 A(n,r),不会把两者混在一起。
原理与规则说明
公式本身只有一行:A(n,r) = n! / (n-r)! = n × (n-1) × (n-2) × … × (n-r+1),一共 r 个因子。页面数据源里登记的表达式写的是阶乘比值 f(n)/f(n-r),数学上完全等价,但本页在实现上不按阶乘比值算,而是用右边的连乘形式。
为什么不用阶乘比值:阶乘比值需要先算出 n!,也就是做 n 次乘法,再除掉 (n-r)!。连乘只需 r 次。当 n=100、r=3 时,先算 100! 要 100 次乘法,连乘只要 3 次,省掉 97 次;当 n=1000、r=3 时省掉 997 次。更关键的是中间量的大小:算 1000! 时中间结果会冲破 double 的上限溢出成 Infinity,而连乘 1000×999×998 只有 3 个因子,最终值 997002000 稳稳落在安全区内。少算的那些因子不仅费时间,还在溢出路径上制造垃圾。
精度处理是本页最关键的一步。JavaScript 的 Number 是 IEEE 754 双精度浮点,能连续精确表示的整数上限是 Number.MAX_SAFE_INTEGER = 9007199254740991,也就是 253−1。超出这个值之后,末尾数字会被静默舍入 —— 不是报错,是给你一个看起来合理但错的数。本页的做法是:先用连乘在 BigInt 上算出精确值,再判断它是否超过 253−1;没超过就按数字显示,超过就在结果区额外挂一条提示,并改用千分位分组的长文本形式输出,保证每一位都可读、不可丢。
两个必须区分的阈值,别混为一谈,这一点决定了排列计算器什么时候必须换算法:
- 253−1 = 9007199254740991 是「整数还能被精确表示」的上限。第一个越界的阶乘是 19! = 121645100408832000,它已经是 18 位数、约为上限的 13 倍。本页算 A(52,13) 时会给出精确值 3954242643911239680000(22 位数),这个数用普通 Number 存是存不住的。
- 1.7976931348623157×10308 是「数值还是有限数」的上限。实测 170! = 7.257415615307994×10306 仍然是有限数,而 171! 直接溢出成
Infinity。所以「阶乘超过 170! 就变成 Infinity」这句话只在讨论阶乘本身时成立;本页的连乘路径远到不了这个位置,因为 r 的上限是 1000,而 A(1000,1000) = 1000! 有 2568 位,BigInt 算得出来但会占 3 KB 内存,页面因此把 n 封在 1000。
还有一个容易被忽略的中间量:位数。A(n,r) 的十进制位数决定了你能不能把它写进论文、写进数据库的 VARCHAR、或者塞进 Excel 单元格(上限 32767 字符)。本页把位数单独列一格,因为它是判断「这个结果还有没有实际用途」最快的指标。
遵循的规范:排列与组合的计数定义来自组合数学的标准表述,符号 A(n,r)(部分教材写 P(n,r))与 C(n,r) 并列;页面采用 IEEE 754-2019 定义的 binary64 交换格式来判定精度边界;大整数运算走 ECMAScript 2020 引入的 BigInt 类型,其语义在 ECMA-262 规范里定义为任意精度整数。三个来源都不是「最新政策」这类会变的东西。
完整示例(数值仅作演示)
示例条件:n = 10,r = 3。逐项算下来:
- 连乘:
10 × 9 × 8 = 720,所以 A(10,3) = 720; - 阶乘比值写法核对:
10! / 7! = 3628800 / 5040 = 720,两条路径一致; - 位数:720 是 3 位数;
- 精度:720 远小于 253−1,落在双精度安全区内,不需要 BigInt 兜底;
- 无序对照:
C(10,3) = 720 ÷ 3! = 720 ÷ 6 = 120,这正是组合计算器会给的数; - 递增一档:r 从 3 变 4,结果乘以 (n−r+1) = 7,得
720 × 7 = 5040,与对照表 r=4 行一致。
这组数字是闭合的:把 r 改成 2,对照表给 90,正好是 720 ÷ 8(因为 n−r+1 = 8);把 r 改成 5,给 30240 = 720 × 8 × 7,也对得上。上面正文的每个数字都能在下方对照表里找到同一行。 以上数值仅作演示,不代表任何真实场景的抽样结果。
输入范围与对照表
下表固定 n = 10,逐档列出 r 从 0 到 10 的结果,把 A(n,r) 与 C(n,r) 并排放,可以直接看出两者比值恒等于 r! 这个规律。表格默认显示 12 行,点「加载更多」展开全部 22 行,也可以导出成 CSV(带 BOM,Excel 直接打开不乱码)。当前输入的 n=10、r=3 那一行会高亮。
| n | r | A(n,r) 有序选法 | C(n,r) 无序对照 | 位数 | 双精度是否安全 |
|---|---|---|---|---|---|
| 10 | 0 | 1 | 1 | 1 | 安全 |
| 10 | 1 | 10 | 10 | 2 | 安全 |
| 10 | 2 | 90 | 45 | 2 | 安全 |
| 10 | 3 | 720 | 120 | 3 | 安全 |
| 10 | 4 | 5040 | 210 | 4 | 安全 |
| 10 | 5 | 30240 | 252 | 5 | 安全 |
| 10 | 6 | 151200 | 210 | 6 | 安全 |
| 10 | 7 | 604800 | 120 | 6 | 安全 |
| 10 | 8 | 1814400 | 45 | 7 | 安全 |
| 10 | 9 | 3628800 | 10 | 7 | 安全 |
| 10 | 10 | 3628800 | 1 | 7 | 安全 |
| 20 | 5 | 1860480 | 15504 | 7 | 安全 |
| 20 | 10 | 670442572800 | 184756 | 12 | 安全 |
| 52 | 5 | 311875200 | 2598960 | 9 | 安全 |
| 52 | 13 | 3954242643911239680000 | 635013559600 | 22 | 超上限 |
| 100 | 3 | 970200 | 161700 | 6 | 安全 |
| 100 | 5 | 75287520 | 7528752 | 8 | 安全 |
| 100 | 10 | 62815650955529472000 | 17310309456440 | 20 | 超上限 |
| 1000 | 3 | 997002000 | 166167000 | 9 | 安全 |
另一组容易混淆的对照:A(n,r) 与 C(n,r) 的比值恒等于 r!,但只在 r 固定时才成立。n=8、r=3 时 A=336、C=56、比值 6;n=8、r=8 时 A=40320、C=1、比值 40320。看表时务必按同一行比较,不要跨行对比比值。
输入范围、边界与精度说明
- r 大于 n 会被直接拒绝,并提示「r 不能大于 n」。数学上 A(n,r) 在 r>n 时无定义(分母 (n−r)! 是负数阶乘),有些实现会静默取绝对值或返回 0,那都是错的 —— 0 会被误读成「一种选法都没有」。本页不这么干。
- n 和 r 的上限都是 1000,且都要求整数。r 的实际上限被 n 卡住,所以 A(1000,1000) 是本页能算的最大值,位数 2568。这个数虽然算得出来,但把 2568 位数字渲染到页面上会挤爆布局,本页在结果区改用千分位分行的形式并提示位数。
- 超出 253−1 时切 BigInt。本页把 9007199254740991 作为判定线,超过就明确标注「超上限,已用 BigInt 精确计算」。对照表里 n=52/r=13 那一行是 22 位数、n=100/r=10 是 20 位数,都属于这一类。给个直观参照:r=3 时要到 n = 208065 才越线,r=5 时 n = 1555 越线,r=8 时 n = 103 就越线 —— r 越大越早触顶。
- 不接受小数。n 与 r 的 step 都设为 1,填 10.5 会被原生校验拦下。排列的「元素个数」在定义上就是非负整数,没有「半个元素」这种说法。
- 结果显示小数位只对极小值有意义。A(n,r) 在数学上恒为整数(除了 r=0 时的 1),所以小数位默认 0。要把它当概率用(比如「随机抽取恰好是某个序列的概率 = 1/A(n,n)」)时,才需要把小数位调大来看 1.239800×10−68 这类极小量。
- 1/A(n,n) 的量级提醒。全排列空间随 n 爆炸:n=5 时 5! = 120,单个指定序列概率 1/120 ≈ 8.33×10−3;n=10 时 10! = 3628800,概率 ≈ 2.76×10−7;n=20 时 20! = 2432902008176640000,概率 ≈ 4.11×10−19;n=52 时 52! 有 68 位,概率约 1.24×10−68。看到这个数量级就该明白:用本页的数去做「穷举验证随机数发生器」是不现实的,那需要的是对数口径或专用检测工具。
常见问题
A(n,r) 和 P(n,r) 是同一个东西吗?
是同一个排列数的两种记号。A 来自英文 Arrangement 的首字母,P 来自 Permutation。不同教材用不同字母,本页统一用 A,因为组合数固定写 C(n,r),配套好记。真正需要区分的是 A 与 C:前者管顺序,后者不管。
为什么组合计算器算出来的数总是我的结果除以 r!?
因为两者只差一个「顺序是否重要」。A(n,r) = C(n,r) × r!,r! 是把 r 个已经选好的元素重新排列的全排列数。如果你的场景里「先选 A 再选 B」和「先选 B 再选 A」是同一件事,那你需要的其实是 C(n,r),请用组合计算器。举例:8 个人里选 3 个组队,队伍成员不分先后,用 C(8,3) = 56;同样 8 个人选 3 个定金银铜牌,名次本身就是要输出的信息,用 A(8,3) = 336。
为什么结果突然变成很长一串数字,还带一条橙色提示?
因为结果超过了 9007199254740991(253−1),也就是 JavaScript 能精确表示的最大整数。再往上走,Number 类型会因为二进制尾数只有 53 位有效数字而把末尾舍入 —— 比如 3954242643911239680000 会被存成 3.95424264391124×1021,看起来只差最后几位,实际差的倍数是 44 万倍量级。本页检测到越界就改用 BigInt 重算,把完整每一位都给你。
r 填 0 为什么结果是 1,不是 0?
因为「什么都不取」只有一种取法 —— 空排列。这是组合数学里的约定,A(n,0) = C(n,0) = 1 对任何 n 都成立。所以 n=0 且 r=0 时结果是 1,不是报错;只有 r 大于 n 才是无定义。
n 最多只能填 1000,为什么不能再大?
两个原因。一是循环成本:A(n,r) 连乘要做 r 次乘法,n 封顶 1000 就意味着最坏情况 1000 次循环,再大页面会卡;二是内存:A(1000,1000) = 1000! 已经有 2568 位,继续往上结果位数增长极快,把它完整渲染到页面上没有实际意义。真要处理更大的 n,行业做法是改用对数口径(算 log 值再取指)只保留数量级,或者干脆用数学软件而不是网页。
我怎么知道填进去的数没被浏览器悄悄改掉?
看结果区「位数」那一格旁边有没有「超上限」标记。有标记说明结果已超出双精度精确范围,页面走的是 BigInt 路径,每一位都可读。另外本页所有输入都设了 min / max / step,浏览器原生校验会先拦一道越界和小数,JS 再判一次并给出具体是哪个字段、允许范围多大的中文提示,不会静默归零。
这个页面会把我填的 n 和 r 上传到哪吗?
哪也不去。全部计算就是一个 BigInt 连乘循环,加上一次和 9007199254740991 的比较,以及一次 1024 以内长度的整数转字符串,没有任何网络请求,也没有引入第三方库。你可以在开发者工具的 Network 面板里确认:页面加载完之后不会再发出任何请求,刷新一下输入也就没了。
我只想知道「有多少种可能」,不关心顺序,用这个页还是用别的?
用组合计算器。本页从头到尾算的都是有序选法,主结果永远是 A(n,r)。虽然结果区会并排给你 C(n,r) 作为对照,但那一列的用途是让你看清差了多少倍、差在 r! 上,不适合直接当答案抄走。另一个常被搞混的场合是「密码有多少种可能」:如果字符不能重复且位置有别,那是排列 A;如果允许重复且只看字符集,那是幂运算,两者都不是本页的公式。