std::pow不能替代快速幂,因其为浮点设计、有精度误差、无O(log n)保证且不支持模运算;手写快速幂需防long long溢出、正确处理mod=1和负数,并优先选用迭代版。

为什么 pow 不能直接替代快速幂
标准库的 std::pow 是为浮点数设计的,对整数大指数(比如 10^9)做 int 幂运算时:一是可能因隐式转换引入精度误差,二是不保证时间复杂度为 O(log n),三是不支持自定义模数。竞赛或密码学场景下必须手写快速幂,尤其是带模的版本。
long long 溢出是递归快速幂最常踩的坑
递归写法简洁,但每次乘法若不做中间取模,a * a 或 a * res 极易溢出——哪怕最终结果在 long long 范围内。例如计算 mod = 1e9+7 下的 power(1e5, 1e5),中间值可能超 9e18。
实操建议:
- 所有乘法前强制转
long long,并立即对mod取模:(1LL * a * b) % mod - 递归函数签名必须带
mod参数,不可只靠全局变量——多组测试时容易错乱 - 基础情况别漏掉
n == 0返回1 % mod,否则power(x, 0)结果错误
位运算迭代版比递归更稳、更快、更省内存
递归有函数调用开销和栈深度风险(虽然 log₂(1e18) ≈ 60 层很安全),而迭代版用 while + 位判断,无栈溢出隐患,也更容易嵌入到 Hot Path 中。
立即学习“C++免费学习笔记(深入)”;
核心逻辑就是把指数 n 当作二进制拆解:n = Σ b_i × 2^i,对应 a^n = Π (a^(2^i)) ^ b_i。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
关键代码片段(带模):
long long binpow(long long a, long long n, long long mod) {
long long res = 1;
a %= mod;
while (n > 0) {
if (n & 1) res = (1LL * res * a) % mod;
a = (1LL * a * a) % mod;
n >>= 1;
}
return res;
}
注意点:
-
a %= mod必须在循环外先做,否则初始a过大会让第一次a * a溢出 -
n & 1判断最低位是否为 1,比n % 2 == 1更快且无符号陷阱 -
n >>= 1等价于n /= 2,但对负数行为不同;题目中n ≥ 0,所以安全
当 mod 不是质数时,快速幂本身不受影响
快速幂只是算 a^n mod m,不依赖 m 是否为质数。只有当你后续要算逆元(比如除法转乘逆元)时,才需要 gcd(a,m)==1。这点常被混淆——算法本身只管乘、取模、位移,跟数论性质无关。
但要注意:
- 如果
mod == 1,直接返回 0(任何数 mod 1 都是 0),避免后续a %= mod导致除零或未定义行为 - 某些题要求结果非负,而 C++ 中
%对负数返回负余数,应写成((x % mod) + mod) % mod - 若
a为负,先a = (a % mod + mod) % mod再进主循环,省得每次判断
真正难的不是写对模板,而是根据输入范围决定要不要用 __int128 做中间乘法,或者改用 Montgomery 乘法——不过那已是更高阶优化了。

















