PHP大数阶乘怎么算_PHP高精度扩展算大阶乘技巧【技巧】

2次阅读

php用bcadd和bcmul可实现大数阶乘,因原生整型64位仅支持至约9.2×10¹⁸,21!即溢出,须用bcmath扩展以字符串形式逐次bcmul累乘,初值为”1″。

PHP大数阶乘怎么算_PHP高精度扩展算大阶乘技巧【技巧】

PHP 用 bcaddbcmul 手写大数阶乘

PHP 原生整型在 64 位系统上最大约 9.2×10¹⁸,21! 就已溢出,直接用 $n * $n-1 会得到 0 或科学计数法错误值。必须切换到任意精度计算——bcmath 扩展是默认启用的最稳妥选择。

核心思路:从 1 开始,逐次用 bcmul 累乘,初始值设为 "1"(字符串),每一步都保持操作数为字符串:

function bigFactorial($n) {     if ($n < 0) return "0";     if ($n <= 1) return "1";     $result = "1";     for ($i = 2; $i <= $n; $i++) {         $result = bcmul($result, (String)$i);     }     return $result; }
  • bcmul 不接受整数参数,传入前务必强转为 string,否则小数值可能被截断(如 bcmul("123", 45) 在某些 PHP 版本中出错)
  • 循环上限别用 $i 配合 <code>int 类型的 $n,超大 $n(比如 10⁵)会导致循环本身超时,这不是精度问题,是算法复杂度瓶颈
  • 结果始终是字符串,不能用 == 直接比数字,要用 bccomp($a, $b) === 0

为什么不用 gmp_fact

gmp_fact($n) 看似更简洁,但它有隐藏限制:参数 $n 必须是整型且不能超过平台 long 范围(通常仍是 2⁶³−1),也就是说,你根本传不进一个“大”$n——gmp_fact(100000) 会因参数溢出失败,而非计算失败。

  • gmp_fact 只适合 $n 且你确认运行环境 <code>long 足够宽的场景
  • 它返回的是 GMP 对象,后续做字符串输出需调用 gmp_strval(),多一层转换
  • 若服务器没启用 gmp 扩展(比 bcmath 更不普及),会直接报 Fatal error: Uncaught Error: Call to undefined function gmp_fact()

性能临界点在哪?怎么预估耗时?

bcmath 阶乘的时间复杂度接近 O(n² log n),因为第 k 步乘法的位数约是 O(k log k),而 bcmul 底层是朴素乘法。实测参考(Intel i7-10875H,PHP 8.2):

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

  • bigFactorial(10000):约 0.15 秒,结果约 36K 位
  • bigFactorial(50000):约 3.8 秒,结果约 213K 位
  • bigFactorial(100000):约 15 秒,结果约 457K 位

超过 10⁵ 后增长陡峭,不是精度不够,是 PHP 解释器和 bcmath 的 C 实现对超长字符串乘法优化有限。此时应考虑改用 Python(math.factorial 底层用 GMP)、或导出为文本后交由外部工具(如 dc)计算。

容易忽略的边界与配置陷阱

bcmath 默认精度(bcscale)只影响除法、模运算等需要小数位的函数,bcmulbcadd 完全无视它——所以别白费劲调 bcscale(100),它对阶乘毫无作用。

  • 确保 bcmath 已启用:extension_loaded('bcmath') 返回 true,否则所有 bc* 函数不可用
  • 输入校验不能只靠 is_int(),用户传来的 "100000" 是字符串,要先 filter_var($n, FILTER_VALIDATE_INT)ctype_digit() 验证再进循环
  • 内存限制:计算 10⁶! 的结果字符串超 5MB,PHP 默认 memory_limit=128M 虽够,但若并发高,可能触发 Fatal error: Allowed memory size exhausted

真正卡住的往往不是“怎么算”,而是没意识到:当 $n > 10⁵ 时,PHP 已不是最优工具,该换语言或分段导出了。

text=ZqhQzanResources