对快速幂算法

79 阅读3分钟

案例一:普通幂计算的效率问题

问题描述:计算 3^13,传统做法需要 12 次乘法:

3^13 = 3*3*3*3*3*3*3*3*3*3*3*3*3

时间复杂度:O(n),指数级增长时效率极低


案例二:快速幂递归分治

目标:将 3^13 分解为更小的问题
二进制分解13 = 8 + 4 + 1(对应二进制 1101)

递归过程

pow(3,13) = pow(3,6)^2 * 3   // 奇次幂分解
           = (pow(3,3)^2)^2 *3 
           = ((pow(3,1)^2 *3)^2)^2 *3
           = ((3^2 *3)^2)^2 *3 = 1594323

操作次数:仅需 5 次乘法(优化约 60%)


案例三:带模运算的场景(密码学应用)

问题描述:计算 7^65537 % 1000000007(RSA 加密典型场景)

传统方法问题

  • 直接计算 7^65537 会导致数值溢出
  • 无法存储如此大的中间值

快速幂迭代法实现

public static void main(String[] args) {
    long base = 7;
    long exponent = 65537;
    long mod = 1000000007;
    
    // 使用迭代法计算
    long result = powIterative(base, exponent, mod);
    System.out.println(result); // 输出 448010174
}

执行过程分解

初始化:result=1, base=7%mod=7, exponent=65537 (二进制 10000000000000001)
循环步骤:
1. exponent末位为1: result = 1*7 =7, base平方后=49, exponent右移=>32768
2. exponent末位为0: 不操作, base平方=2401, exponent=>16384
3. 持续平方直到base=7^(2^16)...
...
最终:合并所有二进制位为1的base值

案例四:矩阵快速幂(斐波那契数列)

问题描述:计算斐波那契数列第 N 项(F(n) = F(n-1) + F(n-2)

矩阵表示

| F(n)   |   =   |1 1|^(n-1) * |F(1)|
| F(n-1)|       |1 0|          |F(0)|

Java 实现关键代码

public static void main(String[] args) {
    System.out.println(fibonacci(10)); // 输出 55
    System.out.println(fibonacci(50)); // 输出 12586269025
}

private static long[][] multiplyMatrix(long[][] a, long[][] b) {
    // 矩阵乘法详细实现(见原始代码)
}

// 矩阵快速幂核心
private static long[][] matrixPower(long[][] matrix, int power) {
    // 使用迭代法计算矩阵幂
}

执行过程分析(以 n=5 为例):

计算 [[1,1],[1,0]]^4 :
- 二进制分解:4 = 100
- 迭代过程:
  1. power=4 (even): 平方矩阵得到 [[2,1],[1,1]]
  2. power=2 (even): 平方得到 [[5,3],[3,2]]
  3. power=1: 结果矩阵与当前矩阵相乘
最终得到 [[5,3],[3,2]],F(5)=5

关键步骤详细解释

递归法核心逻辑

long half = powRecursive(a, b/2, mod); // 分治核心
long result = (half * half) % mod;     // 平方处理
return (b%2==0) ? result : (result*a)%mod; // 奇偶处理
  • 分治策略:将大问题分解为两个相同的小问题(计算 a^(b/2)
  • 平方优化:利用 x^(2n) = (x^n)^2 减少计算量
  • 奇偶处理:当指数为奇数时补乘一个基数

迭代法位运算解析

while (exponent > 0) {
    if ((exponent & 1) == 1) { // 判断二进制最后一位
        result = (result * base) % mod;
    }
    base = (base * base) % mod; // 基数平方
    exponent >>= 1; // 右移一位
}
  • 二进制遍历:从低位到高位扫描指数的二进制位
  • 位与操作exponent & 1 快速判断当前位是否为 1
  • 平方累积:每次循环基数自动升级为 a^2, a^4, a^8...

算法优势对比

方法计算 3^13 操作次数时间复杂度适用场景
传统连乘法12次乘法O(n)小指数计算
递归快速幂5次乘法O(log n)中等规模递归计算
迭代快速幂4次乘法O(log n)大数/高性能需求

错误处理案例

场景:计算 pow(0, 0)(数学未定义)

// 在函数入口添加校验
public static long powIterative(...) {
    if (a == 0 && b == 0) 
        throw new IllegalArgumentException("0^0 is undefined");
    // ...原有逻辑
}

处理负指数

// 扩展支持负指数计算
public static double powWithNegative(double a, long b) {
    if (b < 0) return 1 / powIterative(a, -b, mod);
    // ...调用原有方法
}