快速乘法和快速幂法
1、快速乘法
基本原理:
利用乘法的分配率。定义a=a1+a2+a3+…,则a*b = (a1+a2+a3+…)*b。
使用快速乘法计算X*53。53的二进制表示是 110101,根据乘法分配率X*53可以表示成X*(100000*1+10000*1+1000*0+100*1+10*0+1*1)。假设X=5,可以使用下面的流转图表示。
可以看出 a 的状态方程为 a+=a,b的状态方程为 b>>&1,ans 的状态方程为 ans+=a。因此可以得到一下代码
代码:
//计算a*b
public int quickMultiple(int a,int b){
int ans = 0;
while (b>0){
if((b&1)==1){
ans+=a;
}
b=b>>1;
a+=a;
}
return ans;
}
2、快速乘法取余
**背景:**在计算a * b mod c 时可能在计算a * b时越界,导致无法计算结果。
基本原理:
利用mod 的分配率。a * b mod c 可以表示为a*(b1+b2+b3+…) mod c,进一步可以转化为(a*b1 mod c +a*b2 mod c +…) mod c。
快速乘法的做法刚好是将结果转化为多个数之和,比如265 = 5*1+10*0+20*1+40*0+80*1+160*1,所以5*53 mod 3 =(5+10+20+80+160) mod 3=(5 mod 3 + 10 mod 3 + 20 mod 3 + 80 mod 3 + 160 mod 3) mod 3。因此可以得到以下代码
代码:
//计算 a*b mod c
public int quickMultiple(int a,int b,int c){
int ans = 0;
while (b>0){
if((b&1)==1){
ans=(ans+a)%c;
}
b=b>>1;
a=(a+a)%c;
}
return ans;
}
3、快速幂法
与快速乘法相似,幂运算也可以通过转换变成乘法,比如a^9
=a^(1001)
=a^(1000*1+100*0+10*0+1*1)
。
其流转图如下:
与快速乘法的区别是:
- ans初始值为1
a=a+a
变成a=a*a
ans=ans+a
变成ans=ans*a
代码:
//计算a^b
public int quickPower(int a,int b){
int ans = 1;
while (b>0){
if((b&1)==1){
ans=ans*a;
}
b=b>>1;
a=a*a;
}
return ans;
}
对与每一轮的乘数又可以用快速乘法表示,比如9 = 3*3,所以又可以转化为下列程序:
//使用快速加法计算a^b
public int quickPower(int a,int b){
int ans = 1;
while (b>0){
if((b&1)==1){
ans=quickMultiple(ans,a);
}
b=b>>1;
a=quickMultiple(a,a);
}
return ans;
}
4、快速幂取余
同理,根据快速幂的分配率可以得到a * b mod c = ((a mod c) * (b mod c)) mod c,比如39 mod 5 =((3*1 mod 5 ) * ( 9*0 mod 5) * (81*0 mod 5) *( 6561* 1) mod 5) mod 5。转化为以下代码
代码:
//计算 a^b mod c
public int quickPower(int a,int b,int c){
int ans = 1;
while (b>0){
if((b&1)==1){
ans=(ans*a)%c;
}
b=b>>1;
a=(a*a)%c;
}
return ans;
}
对于每一轮的乘数又可以用快速乘法表示,比如9 = 3*3,所有又可以转化为下列程序:
//使用快速加法计算a^b mod c
public int quickPower(int a,int b,int c){
int ans = 1;
while (b>0){
if((b&1)==1){
ans=(quickMultiple(ans,a,c))%c;
}
b=b>>1;
a=(quickMultiple(a,a,c))%c;
}
return ans;
}