快速幂

思路:

​ 1.每一步都把指数分成两半,而相应的底数做平方运算。这样不仅能把非常大的指数给不断变小,所需要执行的循环次数也变小,而最后表示的结果却一直不会变。

​ 例: 3 10 = 3 × 3 × 3 × 3 × 3 × 3 × 3 × 3 × 3 × 3 3^{10} = 3\times3\times3\times3\times3\times3\times3\times3\times3\times3 310=3×3×3×3×3×3×3×3×3×3 ,尽量想办法把指数变小来,这里的指数为10。

3 10 = ( 3 × 3 ) × ( 3 × 3 ) × ( 3 × 3 ) × ( 3 × 3 ) × ( 3 × 3 ) 3^{10}=(3\times3)\times(3\times3)\times(3\times3)\times(3\times3)\times(3\times3) 310=(3×3)×(3×3)×(3×3)×(3×3)×(3×3)

3 10 = ( 3 × 3 ) 5 3^{10}=(3\times3)^5 310=(3×3)5

3 1 0 = 9 5 3^10=9^5 310=95

​ 2.此时指数由 10 10 10 缩减一半变成了 5 5 5 ,而底数变成了原来的平方,求 3 10 3^{10} 310 原本需要执行 10 10 10 次循环操作,求 9 5 9^5 95 却只需要执行 5 5 5 次循环操作,但是 3 10 3^{10} 310 却等于 9 5 9^5 95,用一次(底数做平方操作)的操作减少了原本一半的循环量,特别是在幂特别大的时候效果非常好,例如 2 10000 = 4 5000 2^{10000}=4^{5000} 210000=45000,底数只是做了一个小小的平方操作,而指数就从 10000 10000 10000 变成了 5000 5000 5000 ,减少了 5000 5000 5000 次的循环操作。

​ 3.现在问题是如何把指数 5 5 5 变成原来的一半, 5 5 5 是一个奇数, 5 5 5 的一半是 2.5 2.5 2.5 ,但是指数不能为小数,因此不能简单粗暴地直接执行 5 / 2 5/2 5/2,然而,这里还有另一种方法能表示 9 5 9^5 95 9 5 = 9 4 × 9 1 9^5=9^4\times9^1 95=94×91

​ 4.此时抽出了一个底数的一次方,这里即为 9 1 9^1 91,这个 9 1 9^1 91 先单独移出来,剩下的 9 4 9^4 94 又能够在执行“缩指数”操作了,把指数缩小一半,底数执行平方操作。 9 5 = 8 1 2 × 9 1 9^5 = 81^2\times9^1 95=812×91

​ 5.把指数缩小一半,底数执行平方操作, 9 5 = 656 1 1 × 9 1 9^5 = 6561^1\times9^1 95=65611×91

​ 6.此时,发现指数又变成了一个奇数1,按照上面对指数为奇数的操作方法,应该抽出了一个底数的一次方,这里即为 656 1 1 6561^1 65611,这个 656 1 1 6561^1 65611 先单独移出来,但是此时指数却变成了 0 0 0 ,也就意味着我们无法再进行“缩指数”操作了。

9 5 = ( 656 1 0 ) × ( 9 1 ) × ( 656 1 1 ) = 1 × ( 9 1 ) × ( 656 1 1 ) = ( 9 1 ) × ( 656 1 1 ) = 9 × 6561 = 59049 9^5=(6561^0)\times(9^1)\times(6561^1)=1\times(9^1)\times(6561^1)=(9^1)\times(6561^1)=9\times6561=59049 95=(65610)×(91)×(65611)=1×(91)×(65611)=(91)×(65611)=9×6561=59049

​ 7.能够发现,最后的结果是 9 × 6561 9\times6561 9×6561。所以能发现一个规律:最后求出的幂结果实际上就是在变化过程中所有当指数为奇数时底数的乘积。

​ 8.继续优化: b b b % 2 2 2== 1 1 1可以用更快的“位运算”来代替,例如: b b b & 1 1 1。因为如果 b b b 为偶数,则其二进制表示的最后一位一定是 0 0 0 ;如果 b b b 是奇数,则其二进制表示的最后一位一定是 1 1 1 。将他们分别与 1 1 1 的二进制做“与”运算,得到的就是 b b b 二进制最后一位的数字了,是 0 0 0 则为偶数,是 1 1 1 则为奇数。例如 9 9 9 是奇数,则 9 9 9 & 1 = 1 1=1 1=1;而 8 8 8是偶数,则 8 8 8 & 1 = 0 1=0 1=0;因此奇偶数的判断就可以用“位运算”来替换了。

​ 9. m = m / 2 m = m / 2 m=m/2 也可以用更快的移位操作来代替,例如: 6 6 6 的四位二进制为 0110 0110 0110 ,而 6 / 2 = 3 6/2=3 6/2=3 3 3 3 的四位二进制为 0011 0011 0011,可以发现, a a a 的一半,结果为 a a a 的二进制码向右移一位,即 m > > = 1 m >>=1 m>>=1

public static long num(long n, long m, long p) {
    long result = 1;
    while (m > 0) {
        if ((m & 1 ) == 1) {
            result = result * n % p;
        }
        m >>= 1;
        n = (n * n) % p;
    }
    return result;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值