排列组合与质数
排列、组合、质数判定、分解质因数与 GCD/LCM,全程 BigInt。
这一页是组合数学与素数的小工作台,全程 BigInt,不碰 eval、不引数学库、不发请求,输入只在本地算。它分三种模式:expr 一行一个整数表达式,认 C/comb/binom、P/perm、后缀 !、fact、gcd、lcm、factors、isprime、nextprime、pow、modpow、mod、abs,外加 + - * / % ** 与括号;prime 一行一个整数,给素性判定与判定来源;range 一行一个区间,把区间内的素数用分段埃氏筛列出来。C(n,k) 不用 n!/k!(n−k)!,而是先用对称性把下标压小(C(n,k)=C(n,n−k),取更小的那个),再做乘法式 r_i = r_(i−1) × (n−k+i) / i。Miller–Rabin 用基集 {2,3,5,7,11,13,17}:当 n 小于 341550071728321 时,这 7 个基全通过就是确定性的证明。
expr 是整数专用页,这条口径用报错来保证:出现小数点直接 not-integer,除不尽的 / 报 not-divisible 并把商和余数都写出来,负指数报 neg-exponent,负数阶乘报 neg-factorial,括号没闭合报 unbalanced-parens,不认的名字报 unknown-func 或 unknown-identifier。任何绝对值超过 2^53−1(9007199254740991,16 位)的结果都会标注位数,并附一个只截前 16 位的科学计数同伴值,明确写着它是「截断近似」——因为 JS 的 Number 在那个量级会丢低位,本页宁可多写一行话也不假装精度还在。n 达到或超过确定性界时改用 20 个固定基 {2,3,…,71},输出会明说结论是概率性的,因为基是固定值而非随机取,所以它是「probable prime」而不是证明。factors 的试除除数触到 500000 就打印「未完全分解」,把触顶的除数与上限数值都写出来,再让 Miller–Rabin 接手剩余值并注明结论来源。
排列组合与质数怎么用
- expr:一行一个式子:默认样本 C(52,5)、P(10,3)、gcd(462,1071)、factors(2**61-1) 覆盖四条主要管道。函数名大小写不敏感,c、C、comb、binom 是同一个;2**61-1 这种写法先算幂再算减法,且全程 BigInt。脏行不会中断其它行,输出里以「错误[名字] 说明」的形式留在原位,提示条会汇总几行没算出来。行数超过 200 时只算前 200 行并在 meta 与提示里说明。守卫按明面上的数值来:单次运算最多 20000 步循环、结果最多 20000 位十进制、单行表达式 400 字符、一次最多处理 200 行,超了就报错或截断并说明,不会把一个按钮变成把标签页算死的开关。
- prime:一行一个整数:每行给出「是素数 / 是合数」+用了哪组基+为什么这组基在这个范围内算证明(或为什么只能算概率性)。合数还会附一条最小因子链(试除得到),超过 2^53−1 的数另外标位数。想亲眼看见「费马被骗」与「MR 抓得住」的差别,就并排放 561 与 2047。Carmichael 数(561 = 3×11×17、1105、1729、2465、2821、6601…)对所有互素的基都满足费马小定理,费马单基测试会在它们身上误判,而 Miller–Rabin 能抓出来。
- range:一行一个区间:写法接受 a b、a-b、a,b、a;b、a..b 与 a.b,两个数顺序反了会自动调换并在提示里点名。每行输出素数个数、完整列表、所用的 √hi 小素数表信息与区间长度对上限的关系;空区间(上界小于 2)会明确给「无」。1-100000000000000 这类跨度超限的写法得到的是 span-too-wide 错误行,而不是一个转不动的页面。
- 「给出计算过程」打印什么:打开「给出计算过程」,输出里打印的是这条真实轨迹(第 0 步 r = 1、第 i 步 r = 旧值 × 分子 ÷ i = 新值),而不是事后编的说明;gcd 附带欧几里得辗转相除的余数链,modpow 说明平方-乘的步数与指数位宽。边界都按定义钉死:k > n 得 0 并且即使关掉过程也会解释「从 n 个里选 k 个选不出来,这是定义不是错误」,C(0,0) = 1(空乘积),0! = 1,负数阶乘报错。
- factors 与 range 各自用什么算法:factors 用最朴素的口径:先除尽 2,再从 3 起按奇数递增试除,直到「除数的平方超过剩余值」或除数触到 500000 为止;前者意味着剩余值本身就是素因子(这是试除给出的证明),直接收进乘积里;后者会打印「未完全分解」、把触顶的除数与上限数值都写出来,再让 Miller–Rabin 接手剩余值并注明结论来源。range 模式用分段埃氏筛:先筛出 √hi 以内的小素数,再用它们逐个划 [lo,hi] 上的倍数,跨度上限 200000、上界 10^12,下界小于 2 时不动数据只说明「实际从 2 开始筛」,因为 0、1 与负数按定义都不是素数。
常见问题
为什么不直接算 n!/(k!(n−k)!)?它不是更直观吗?
直观但它把中间值放大到无意义的地步:C(100,50) 的结果只有 30 位,而 100! 有 158 位,除完还要再掉回去;更麻烦的是这条式子还暗示「可以先算浮点阶乘再相除」,那样一来第 170 项起就溢出成 Infinity,结果一片模糊。乘法式 r_i = r_(i−1) × (n−k+i)/i 的每一步都是精确整除(r_i 本身就是一个组合数),所以既不需要取整技巧也不需要模逆元,中间值单调增长且不超过最终结果,还能把约分过程原样打印出来。另外它顺手解决了定义边界:k > n 直接是 0,C(0,0) 与 0! 都是空乘积 1。算 C(100,50) 只要 50 步,最大的中间量就是结果本身 100891344545564193334812497256(30 位),而按阶乘式先要造出 158 位的 100!。
Miller–Rabin 说「是素数」,我能信到几成?
分两段。n 小于 341550071728321 时,基 {2,3,5,7,11,13,17} 全部通过就是数学上的证明,这个界是这组基的最小强伪素数,所以范围内不存在反例——这也是本页把这个数原样打进输出的原因。到了界以上,本页换成 20 个固定基,理论上每个基最多放过 1/4 的合数,连起来误判上界约 4^−20(约 9.1e-13),但因为基是写死的、不是每次随机取,严格来说它是强伪素数测试而不是概率证明,所以输出标「概率性素数」。如果你要的是可复核的证明,请用带证书的输出或专门的证明工具,本页不会把概率说成定理。
factors(2**61-1) 为什么不给我完整分解?
因为试除要在可接受的时间里走完,而 √(2^61−1) 大约是 1.5×10^9:要把这个上限走满,得做几亿次大整数取模,页面会先卡死。本页把试除的除数上限定在 500000,走到顶还没剩下「除数平方已超过剩余值」这个证明条件时,就直接承认「未完全分解」,把触顶的除数与上限数值一起打出来,再让 Miller–Rabin 判剩余值——2^61−1 大于确定性界,所以那句结论同时标着概率性。这个数本身是已知的梅森素数,页面的回答是「我没在试除范围内找到因子,剩下的判定来自 MR,来源是概率性的」,而不是假装分解完成。想看完整的因子链,试 561(= 3 × 11 × 17)或 2047(= 23 × 89)。
为什么把强伪素数那一串数原样打进输出?
这个界正是该基集 {2,3,5,7,11,13,17} 的最小强伪素数(OEIS A014233 的第 7 项),本页把它和前面的 2047、1373653、25326001、3215031751、2152302898747、3474749660383 一起当用例跑过——这些数各自能通过对应那组基,却都是合数,这正是「基集与界必须成对说」的原因。到了界以上,2^61−1 = 2305843009213693951 就是概率性分支的活样本。