幂模运算

在众多的加密算法中都需要进行幂的取模运算,比如在RSA算法中需要计算ne mod N,我们称之为幂模算法。

我经常第一个想到的算法就是用pow(),最后发现根本得不到想要的结果,测试才方向是因为溢出。

当指数很大时我们采用两种方法。

方法一

利用性质:a*b%m=a*(b%m)%m
a^b%m=(a%m)^b%m
int mod(int a,int b,int m){
    int result = 1;
    for(int i=0;i<b;i++) {
        result = (result*a) %m;
    }
    return result;
}
但当b很大时这个方法循环的次数还是相对太大,不是很理想。

方法二

进一步研究指数b的二进制表示发现,对任意的整数b都可表示为:


  • n表示b的实际二进制位数
  • bi表示该位是0或1

因此,ab可表示为:

即用b的每一位表示a的每一项,而对任意相邻的两项存在平方关系,即:

因此我们构造下面的算法:

  • 把b转换为二进制表示,并从右至左扫描其每一位(从低到高)
  • 当扫描到第i位时,根据计算a的第i项的模,这里先是假设多有的bi都是1,记录下来,当真正的bi为1时供result使用

    base变量表示第i-1位时计算出的模。
  • 如果第i位为1,即bi=1,则表示该位需要参与模运算,计算结果 result = (result*base) mod m;其中result为前i-1次的计算结果。
int mod(int a,int b,int m){
    int result = 1;
    int base = a;
    while(b>0){
         if(b & 1==1){//与1按位与
            result = (result*base) % m;
         }
         base = (base*base) %m;//难点在这
         b>>=1;//相当于除2
    }
    return result;
}
把时间复杂度降到了lgb,大大优于方法一。



其实还需要考虑m为负数的情况

leetcode   50. Pow(x, n)
Implement pow(xn).

为什么new要用unsigned long long?因为n可能是INT_MIN
class Solution {
public:
	double myPow(double x, int n) {
		double res = 1;
		unsigned int newn = n;
		if (n < 0) {
			x = 1 / x;
			newn = -n;
		}
		while (newn){
			if (newn & 1){
				res *= x;
			}
			x *= x;
			newn >>= 1;
		}

		return res;
	}
};






  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值