快速幂递归易栈溢出主因是编译器未优化尾递归且每次调用压入局部变量和返回地址;MOD=1时须特判返回0,否则base变0导致结果错误。

快速幂的递归写法为什么容易栈溢出
递归实现 pow_mod 看起来简洁,但深度为 log₂(n) 的调用栈在 n 达到 1e18 时也才约 60 层——问题不在深度,而在编译器没做尾递归优化,且每次调用都压入局部变量和返回地址。更关键的是,有人把递归基写成 n == 0 却忘了处理 n ,结果传入负指数直接无限递归。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 一律用迭代(二进制拆分)代替递归,避免任何栈风险
- 指数必须先取模
phi(MOD)(仅当底数与 MOD 互质时才合法),否则不能乱约 - 若 MOD 不是质数且底数不互质,
n == 0时结果不是 1 而是未定义,得单独判
long long 溢出发生在哪一行
最常翻车的位置是乘法:哪怕 a 和 b 都小于 MOD,a * b 也可能远超 LLONG_MAX(约 9e18)。比如 MOD = 1e9+7,a = b = 1e9,乘积就是 1e18,刚好卡线;但若 MOD = 1e12,a = b = 1e7,乘积才 1e14 —— 表面安全,实际已越界。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 用
__int128(GCC/Clang 支持)做中间乘,再取模:return (__int128)a * b % MOD - 无
__int128时用“龟速乘”(二进制拆分加法),时间多 log₂(b),但保安全 - 别信“MOD 小就不用防”,只要 a、b 接近 sqrt(LLONG_MAX),乘就可能炸
大数幂(string 输入)怎么接快速幂
输入是字符串形式的大指数(如 "12345678901234567890"),没法转 long long。这时候不能硬转,得边读边模——但模谁?不是 MOD,而是欧拉函数 phi(MOD)(用于降幂),前提是底数 a 与 MOD 互质。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 先算
phi = euler_phi(MOD),再逐位解析字符串指数 s:res = (res * 10 + (s[i] - '0')) % phi - 若 a 与 MOD 不互质,且指数 ≥ phi,则要用扩展欧拉定理:结果为
pow_mod(a, exp % phi + phi, MOD)(exp > phi 时) - 字符串长度超过 20 就别试
stoll,它会静默截断或抛异常,不报错才是最危险的
MOD=1 怎么不出错
所有数对 1 取模都是 0,但快速幂里如果漏判 MOD == 1,循环中 base %= MOD 会让 base 变 0,后续全算 0,而正确答案应该是 0(a⁰ 除外,但 a⁰ mod 1 也是 0)。更隐蔽的是,phi(1) == 1,降幂时若没特判,会导致错误地把指数模 1 成 0,再算 a⁰ = 1,最终返回 1 mod 1 = 0 —— 碰巧对了,但逻辑已崩。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 入口第一行加
if (MOD == 1) return 0;,彻底堵死 - 不要依赖“数学上成立”就跳过边界,MOD 是运行时变量,可能来自输入或配置
- 测试用例至少含 MOD=1、MOD=2、MOD=998244353、MOD=1000000007 四种
真正麻烦的从来不是算法主干,而是指数为 0、MOD 为 1、底数为 0、负指数、非互质这些分支——它们不常出现,但一出就是线上事故。











