快速幂算法

背景

  • 计算幂指数时,如计算 2 10 2^{10} 210 ,可以2乘以10次,这样的话复杂度高。
  • 也可以先计算 2 2 2^2 22,然后中间结果再平方 2 2 2 2^{2^{2}} 222 ,即先算2次方,然后再直接算4次方,然后算8次方,每次直接翻倍。这样的话复杂度降低了很多。这种方法叫做快速幂指数算法。
  • 在计算 2 100 2^{100} 2100 时,普通算法需要计算100次乘法,而快速幂指数计算6次就到了64次方,一共也只需要计算9次。

方法

  • 下面介绍快速幂指数方法。
  • 首先我们先看 2 10 2^{10} 210,结果我们都知道等于1024。
  • 在计算时,过程如下:
    • 1、 取中间变量t(temp),结果变量r(result),指数p(power),底数b(base)。
    • 2、初始化,b = 2;p = 10; t = b 1 t = b ^ 1 t=b1,r = 1;
    • 3、注意到,p = 10的二进制为 p = 1010(bit),1010(bit) = 1000(bit) + 0010(bit)。
    • 4、因此, 2 1010 ( b i t ) = 2 1000 ( b i t ) × 2 0010 ( b i t ) 2 ^ {1010(bit)} = 2 ^ {1000(bit)} \times 2 ^ {0010(bit)} 21010(bit)=21000(bit)×20010(bit) 。即 2 10 = 2 8 × 2 2 2^{10} = 2^8 \times 2^2 210=28×22。包括2次方项和8次方项。
    • 5、我们进行翻倍计算。目前 t = b 1 t = b ^ 1 t=b1 ,令 t *= t,则 t = b 2 t = b ^ 2 t=b2 。由于结果包含2次方项,因此 r *= t,则 r = b 2 r = b ^ 2 r=b2
    • 7、继续翻倍,令 t *= t,则 t = b 4 t = b ^ 4 t=b4
    • 8、继续翻倍,令 t *= t,则 t = b 8 t = b ^ 8 t=b8 。由于结果包含8次方项,因此 r *= t,则 r = b 10 r = b ^ {10} r=b10
  • 以上过程,写成代码如下:
    #include <iostream>
    using namespace std;
    int QuickPower(int b, int p) {
        int t = b;
        int r = 1;
    
        while(p) {
            if(p & 1) {
                r *= t;
                p -= 1;
            } else {
                t *= t;
                p >>= 1;
            }
        }
        return r;
    }
    
    int main() {
        cout << QuickPower(2,10);
        return 0;
    }
    
  • 以上代码中,if(p & 1)作用是用来检测结果中是否包含改2次方项,如果包含,则把其乘以到结果中。

余数定理

  • 在计算2的100次方时,结果会溢出。
  • 因此经常要求结果按多少多少取余数。余数定理如下:(a * b)%c = ((a%c) * (b%c)) % c;
  • 相乘的结果,等于各数余数的结果相乘再取余。
  • 因此上面代码可以改为每次相乘后都取余数,假设按1000取余:
    #include <iostream>
    using namespace std;
    int QuickPower(int b, int p) {
        int t = b;
        int r = 1;
    
        while(p) {
            if(p & 1) {
                r *= t;
                r %= 1000;
                p -= 1;
            } else {
                t *= t;
                t %= 1000;
                p >>= 1;
            }
        }
        return r;
    }
    
    int main() {
        cout << QuickPower(2,100);
    
        return 0;
    }
    
  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天城寺电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值