快速幂||取余运算

快速幂算法能帮我们算出指数非常大的幂,传统的求幂算法之所以时间复杂度非常高(为O(指数n)),就是因为当指数n非常大的时候,需要执行的循环操作次数也非常大。

核心思想:

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

原理一:

过程是这样的:

 实现:

int quickPower(int a, int b)//是求a的b次方
{
	int ans = 1, base = a;//ans为答案,base为a^(2^n)
	while(b > 0)//b是一个变化的二进制数,如果还没有用完
    {
		if(b & 1)//&是位运算,b&1表示b在二进制下最后一位是不是1,如果是:
			ans *= base;//把ans乘上对应的a^(2^n)
		
        base *= base;//base自乘,由a^(2^n)变成a^(2^(n+1))
		b >>= 1;//位运算,b右移一位,如101变成10(把最右边的1移掉了),10010变成1001。现在b在二进制下最后一位是刚刚的倒数第二位。结合上面b & 1食用更佳
	}
	return ans;
}

原理二:

参照下面例题讲解:

 模拟一下:

 代码和上面一样,因为b&1和mod 2 ==1 等效。b/=2与b>>=1等效

取余运算:

快速幂经常要结合取余运算。这里也讲一点。

取余运算有一些好用的性质,包括:

证明都很简单,如果要说服自己的话拿起笔试试吧。可设A=kA​×b+RA​……

于是快速幂过程中可以

	while(b > 0)
    {
		if(b & 1)
        {
			ans *= base;
            ans %= m;
    	}
		
        base *= base;
        base %= m;
		b >>= 1;
	}

能保证这样下来最后的结果与“先乘到最后,再取余”的结果一样。 

案例:

3^10=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*3)^5

3^10=9^5

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

//现在我们的问题是如何把指数5变成原来的一半,5是一个奇数,5的一半是2.5,但是我们知道,指数不能为小数,因此我们不能这么简单粗暴的直接执行5/2,然而,这里还有另一种方法能表示9^5

9^5=(9^4)*(9^1)

//此时我们抽出了一个底数的一次方,这里即为9^1,这个9^1我们先单独移出来,剩下的9^4又能够在执行“缩指数”操作了,把指数缩小一半,底数执行平方操作

9^5=(81^2)*(9^1)

//把指数缩小一半,底数执行平方操作

9^5=(6561^1)*(9^1)

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

9^5=(6561^0)*(9^1)*(6561^1)=1*(9^1)*(6561^1)=(9^1)*(6561^1)=9*6561=59049

我们能够发现,最后的结果是9*6561,而9是怎么产生的?是不是当指数为奇数5时,此时底数为9。那6561又是怎么产生的呢?是不是当指数为奇数1时,此时的底数为6561。所以我们能发现一个规律:最后求出的幂结果实际上就是在变化过程中所有当指数为奇数时底数的乘积。
 

代码实现:

long long fastPower(long long base, long long power) {
    long long result = 1;
    while (power > 0) {
        if (power % 2 == 0) {
            //如果指数为偶数
            power = power / 2;//把指数缩小为一半
            base = base * base % 1000;//底数变大成原来的平方
        } else {
            //如果指数为奇数
            power = power - 1;//把指数减去1,使其变成一个偶数
            result = result * base % 1000;//此时记得要把指数为奇数时分离出来的底数的一次方收集好
            power = power / 2;//此时指数为偶数,可以继续执行操作
            base = base * base % 1000;
        }
    }
    return result;
}

 优化:
虽然上面的快速幂算法效率已经很高了,但是我们仍然能够再一次的对其进行“压榨级别”的优化。我们上面的代码看起来仍然有些地方可以再进一步地进行简化,例如在if和else代码块中仍然有重复性的代码:

       power = power / 2;
       base = base * base % 1000;

 而

            power = power - 1;//把指数减去1,使其变成一个偶数
            power = power / 2;

可以压缩成一句

             power = power / 2;

因为power是一个整数,例如当power是奇数5时,power-1=4,power/2=2;而如果我们直接用power/2=5/2=2。在整型运算中得到的结果是一样的,因此,我们的代码可以压缩成下面这样: 

long long fastPower(long long base, long long power) {
    long long result = 1;
    while (power > 0) {
        if (power % 2 == 1) {
            result = result * base % 1000;
        }
        power = power / 2;
        base = (base * base) % 1000;
    }
    return result;
}

 再优化:

在C语言中,power%2==1可以用更快的“位运算”来代替,例如:power&1。因为如果power为偶数,则其二进制表示的最后一位一定是0;如果power是奇数,则其二进制表示的最后一位一定是1。将他们分别与1的二进制做“与”运算,得到的就是power二进制最后一位的数字了,是0则为偶数,是1则为奇数。例如5是奇数,则5&1=1;而6是偶数,则6&1=0;因此奇偶数的判断就可以用“位运算”来替换了。

同样,对于power=power/2来说,也可以用更快的“位运算”进行替代,我们只要把power的二进制表示向右移动1位就能变成原来的一半了。 

 代码:

long long fastPower(long long base, long long power) {
    long long result = 1;
    while (power > 0) {
        if (power & 1) {//此处等价于if(power%2==1)
            result = result * base % 1000;
        }
        power >>= 1;//此处等价于power=power/2
        base = (base * base) % 1000;
    }
    return result;
}

 

 

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 快速幂是一种用于快速计算幂运算算法,其基本思想是将指数进行二进制拆分,然后利用指数的二进制表示来快速计算幂运算。在计算过程中,可以利用取余运算来避免数值溢出,提高计算效率。快速幂算法的时间复杂度为O(logn)。 具体实现时,可以使用递归或循环的方式来实现快速幂算法。在递归实现中,需要注意处理指数为负数的情况。在循环实现中,需要注意处理指数为0的情况。 取余运算可以使用%运算符来实现,其含义是求两个数相除的余数。在快速幂算法中,取余运算可以避免数值溢出,提高计算效率。需要注意的是,在取余运算中,除数不能为0。 综上所述,快速幂算法取余运算是计算幂运算时常用的算法运算符,能够提高计算效率,避免数值溢出。 ### 回答2: 快速幂算法是一种优化指数运算算法,通常用于对大整数进行多次乘方运算。该算法的基本思想是将指数拆分成二进制的形式,然后利用指数的二进制表示逐步计算。 具体来说,假设要计算a^b mod c的值,其中a、b、c均为正整数,那么可以先将b转换为二进制的形式,然后从右往左遍历这个二进制数,每次将当前位的值乘到结果中,同时对结果取模,然后将底数a自乘一次,且也要对结果取模。最终得到的结果就是a^b mod c的值。 例如,假设要计算3^13 mod 7的值,将13转换为二进制的形式得到1101,从右往左遍历这个二进制数,开始时结果为1,底数为3,当前位是1,那么将3乘到结果中,并对结果取模得到3,底数自乘得到9 mod 7 = 2;下一位是0,直接将底数自乘,即2*2 mod 7 = 4;再下一位是1,将底数自乘得到16 mod 7 = 2,同时将2乘入结果,结果为3×2 mod 7 = 6;最后一位是1,将底数自乘得到4 mod 7 = 4,同时将4乘入结果,结果为6×4 mod 7 = 3,因此3^13 mod 7的值为3。 快速幂算法的优点是可以快速地计算指数运算,具有较好的时间复杂度。同时,取模运算的存在可以避免产生过多的中间结果,节省了空间复杂度。然而,快速幂算法的缺点是需要将指数转换为二进制形式,这可能会增加算法的编程难度。 ### 回答3: 快速幂是一种用于求解幂运算的快速算法。在进行取余运算时,快速幂算法能够通过对结果取模,使得计算结果更为精确。在计算大数据的幂的运算时,常常可以使用快速幂算法来进行加速运算快速幂算法可以使用递归的方式实现,也可以使用循环的方式实现。递归实现的代码比较简单,但是存在栈空间过大的问题;循环实现的代码虽然有一定的难度,但是能够避免栈空间过大的问题。 在进行取余运算时,我们需要注意的是,如果运算的两个数都很大,那么我们在计算结果时需要特别小心。因为如果直接进行计算,可能会导致数据类型溢出,进而产生错误的结果。为了避免这种情况,我们可以在进行计算时,对结果进行取模处理。 在进行取模运算时,我们需要使用取模定理,也就是(a*b)%p=(a%p)*(b%p)%p。通过这种方式,可以使得计算结果更为精确,也可以避免数据类型溢出的情况发生。如果无法使用取模定理,则需要使用高精度的算法进行取余运算。 总而言之,快速幂算法是一种非常有效的幂运算算法,可以快速地计算出大数据的幂运算结果。在进行取余运算时,需要特别注意数据类型溢出的问题,在进行计算时需要特别小心。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值