
本文详解如何安全计算 n! mod (10⁹+7),避免中间结果整数溢出,通过循环中及时取模确保 long 类型不越界,并提供可扩展的模乘优化写法。
本文详解如何安全计算 n! mod (10⁹+7),避免中间结果整数溢出,通过循环中及时取模确保 long 类型不越界,并提供可扩展的模乘优化写法。
在计算阶乘(即前 n 个正整数的乘积)并对大质数(如 (10^9 + 7))取模时,直接累乘再取模极易导致中间结果溢出——即使使用 long 类型(Java/C++ 中通常为 64 位),当 (n \geq 21) 时,(n!) 就已远超 Long.MAX_VALUE(约 (9.2 \times 10^{18})),造成静默溢出,最终结果错误。
✅ 正确做法是:在每次乘法后立即取模,利用模运算的分配律: [ (a \times b) \bmod p = \big((a \bmod p) \times (b \bmod p)\big) \bmod p ] 这能保证每一步的中间值始终严格小于模数 (p = 10^9 + 7),从而完全规避溢出风险。
以下是推荐的实现(以 Java 为例,其他语言逻辑一致):
public static long factorialMod(int n, long MOD) {
if (n <p>⚠️ 注意事项:</p>
- 起始值与循环范围需准确:n=0 和 n=1 时结果均为 1;循环应从 i = 2 开始(或统一从 i = 1 开始,但初始 ans=1 已隐含乘 1);
- 模数定义为 long 常量:1000000007L 防止整型字面量溢出;
- 无需双重取模:(ans % p) * (i % p) 在 i
- 极端场景优化:若 n ≥ p,根据威尔逊定理,n! mod p = 0(因 p 为质数且必为某个因子),可提前返回 0,提升性能。
? 总结:模运算不是仅在最后执行的“收尾操作”,而是保障中间过程数值稳定的关键防御机制。坚持“每步取模”,是处理大数阶乘、幂运算、组合数等模算术问题的黄金准则。











