该问题出自《C语言名题精选百则技巧篇》
题目:如果n和m是正整数,求m^n.
m^n就是把m连乘n次,这是一个很没有效率的方法,我们要找到更有效率的办法。
第一种方法 递归
很容易可以注意到,x^4可以写成x^2 * x^2, 通过x*x*x*x的方法要进行3次乘法,而x^2 * x^2只需要进行两次乘法,可以减少乘法运算的数量。因此我们可以把x^m里边偶数次幂的部分分离出来。
m^n = 1 n=0
m^n = (m^k)^2 n=2k(偶数)
m^n = m*m^2k n=2k+1(奇数)
用递归函数也可以分成三个部分,第一部分看n是否为0,;第二部分看n是否是偶数,如果是,就求m的n/2次方(递归),算出来的结果再平方就是m^n.
;当n是个奇数时,n=2k+1,m*m^2k,递归调用自己去计算m^2k,依此写出的函数为recursive_power()函数。
第二种方法 非递归方法
可以把m^n的幂数n转化成二进制,比如n=45,则45 = 101101 = 1*2^5+0*2^4+1*2^3+1*2^2+0*2^1+1*2^0。则
m^n = m^(2^5)* m^(2^3) * m^(2^1) * m^(2^0)值为1的那一位(比如第i位,从右往左为0,1,2,3),在m的指数中就有m^(2^i)那一项,因此我们可以把m^(2^0),m^(2^1),m^(2^2),...,m^(2^(i+1)).求出来,这正好对应着n的二进制表示中,从右到左的顺序,如果在n的二进制表示中第i位是1,那么就把m^(2^i)乘到一个用来保存最终结果的变量中(初值为1),因此当n的每一位都查完以后,就有了答案了。
如何求m^(2^0),m^(2^1),m^(2^2),...,m^(2^i)?
m^(2^(i+1)) = m^((2^i)*2) = (m^(2^i))^2.因此只要求出m^(2^i),就能得到 m^(2^(i+1)) 。
比如n=45=101101, temp初始为1
n最低位为1,temp = temp*m = m,使n右移一位n = 10110,m=m*m= m^2,
n最低位为0,temp不变,n右移一位n=1011,m=m*m = m^2 *m^2 = m^4。
n最低位为1,temp = temp*m = m^5,n右移一位n=101,m=m*m = m^4 *m^4 = m^8
n最低位为1,temp = temp*m = m^13,n右移一位n=10, m=m*m = m^8 *m^8 = m^16
n最低位为0,temp 不变,n右移一位n=1,m=m*m = m^16 *m^16= m^32。
n最低位为1,temp = temp*m = m^45. n右移一位,n=0结束。
依此写出的函数为iterative_power()函数。
#include <stdio.h>
#include <stdlib.h>
unsigned long recursive_power(unsigned long m,unsigned long n)
{
unsigned long temp;
if(n==0)
return 1;
else if(n%2==0){
temp = recursive_power(m,n/2);
return temp*temp;
}else
return m*recursive_power(m,n-1);
}
unsigned long iterative_power(unsigned long m,unsigned long n)
{
unsigned long temp =1;
while(n>0){
if(n&0x01UL == 1)
temp *=m;
m*=m;
n>>=1;
}
return temp;
}
int main(int argc,char *argv[])
{
int m,n;
unsigned long answer;
printf("\nR_POWER Program:m^n");
printf("\nInput m -->");
scanf("%d",&m);
printf("Input n -->");
scanf("%d",&n);
//answer = recursive_power(m,n);
answer = iterative_power(m,n);
printf("m^n = %d^%d = %ld",m,n,answer);
while(1)
getchar();
return 0;
}
运算结果