快速乘算法/快速幂算法详解

快速乘算法

问题

已知正整数a、b、mod,求(a * b) % mod = ?
其中,a、b的数量级很大,接近甚至大于mod的数量级

a * b可能会溢出, 所以不方便直接相乘

解决方案

化乘法为加法,a * b相当于b个a相加

暴力算法

int quik_mul(int a, int b, int mod) {
	long long output = 0;
	for (int i = 0; i != b; i++)
		output = (output + a) % mod;
	return output;
}

以上代码时间复杂度为O(b),b的数量级很大,不可行

手算思路

为优化算法,先思考我们如何手算a * b?

例:求10026 * 20202.

解:10026 * 20202
=(10026 * 2)*(20202 / 2) = 20052 * 10101
20202是偶数,提因数2乘10026
=20052 + 20052 * 10100 = 20052 + 40104 * 5050
10101是奇数,先用乘法分配律凑偶,再提因数2乘20052
按照以上奇偶规则,继续计算,同时把凑偶时拆出去的数括起来
=(20052) + 80208 * 2525
=(20052 + 80208) + 80208 * 2524
=(20052 + 80208) + 160416 * 1262
=(20052 + 80208) + 320832 * 631
=(20052 + 80208 + 320832) + 320832 * 630

把括号里的数用一个变量单独存储,循环计算直到括号外没有数,此时括号里的和就是答案

代码实现

int quik_mul(int a, int b, int mod) {
	long long output = 0;	//存储括号里的和的变量
	while (b) {	//当括号外有数时,b不为0
		//当b为偶数时,提取b的因数2乘给a
		if (0 == b % 2) {	
			a = (a*a) % mod;
			b = b / 2;
		}
		//当b为奇数时,提取1个a到括号(output)里,b-1为偶数,再提取b的因数2乘给a
		else {
			output = (output + a) % mod;
			a = (a*a) % mod;
			b = (b - 1) / 2;
		}
	}
	return output;	//括号里的和就是答案
}

用位运算改进代码

int quik_mul(int a, int b, int mod) {
	long long output = 0;
	while (b) {
		if (b & 1)
			output = (output + a) % mod;
		a <<= 1;
		b >>= 1;
	}
	return output;
}

快速幂算法

快速幂算法的思路和快速乘算法的思路类似,理解了上面的快速乘算法,再理解快速幂算法就轻而易举了

问题

已知正整数a、b、mod,求(a ^ b) % mod = ?
其中,a、b的数量级很大,接近甚至大于mod的数量级

暴力算法

int quik_power(int a, int b, int mod) {
	long long output = 1;	//注意初始值是1不是0
	for (int i = 0; i != b; i++)
		output = (output*a) % mod;
	return output;
}

手算思路

例:求3 ^ 18.

解:3 ^ 18
=(3 ^ 2)^(18 / 2)=9 ^ 9
18是偶数,提因数2
=(9) * 9 ^ 8
9是奇数,先用乘法结合律凑偶,再提因数2
=(9) * 81 ^ 4
=(9) * 6561 ^ 2(6561 = 81 * 81)
=(9 * 43046721)
把凑偶时拆出去的数括起来,循环计算直到括号外没有数,此时括号里的积就是答案

代码实现

int quik_power(int a, int b, int mod) {
	long long output = 1;
	while (b) {
		if (0 == b % 2) {
			b /= 2;
			a = (a*a) % mod;
		}
		else {
			output = (output*a) % mod;
			b = (b - 1) / 2;
			a = (a*a) % mod;
		}
	}
	return output;
}

用位运算改进代码

int quik_power(int a, int b, int mod) {
	long long output = 1;
	while (b) {
		if (b & 1)
			output = (output*a) % mod;
		b >>= 1;
		a = (a*a) % mod;
	}
	return output;
}

推广

快速幂算法可以推广到用户定义的数据类型,如矩阵快速幂

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值