真的很尴尬!!我只是不理解下面的小程序的工作,它使用递归来计算数字“a”(“a”上升到幂“b”)的幂。请解释逻辑在这个函数后面使用。我不明白使用“x * x”参数,n / 2参数和“n modulo 2”部分。请为我解剖。
#include<stdio.h>
int foo(int,int);
int main() {
int a,b;
printf("Enter number a and its power b\n");
scanf("%d%d",&a,&b);
printf("a raised to b is %d", foo(a,b));
return 0;
}
int foo ( int x , int n) {
int val=1;
if(n>0) {
if (n%2 == 1)
val = val *x;
val = val * foo(x*x , n/2);
}
return val;
}
答案 0 :(得分:6)
这种递归背后的想法是, b =(a 2 ) b / 2 和 b < / sup> = a(a 2 )(b-1)/ 2 。
根据b是奇数还是偶数(即n%2 == 1
部分),您可以选择其中一个公式来确保b / 2或(b-1)/ 2仍然是整数。请注意,对于奇数n,代码中的n/2
实际上是(n-1)/ 2,因为整数除法会自动向下舍入。
此递归终止,因为指数随着每一步逐渐变小。
答案 1 :(得分:4)
这利用了x^23
等权力可以改写为x^16 * x^4 * x^2 * x^1
现在计算x^16
非常简单,因为它只是(((x^2)^2)^2)^2
,只有4次乘法而不是计算x * x * x * ... 16 times ... * x
。
现在请注意,在计算x^16
时,您还需要运行x^4
和x^2
来计算您的号码。所以最后,你只用了7次乘法而不是22次计算x^23
。
现在n % 2
和n / 2
进入图片的位置是判断2的幂是否在n中(在我们的例子中,在23的二进制表示中是8?no)。
所以你只需要遍历n的位。你每次都是x,如果你正在查看当前n位中的1,你将平方数乘以你的结果。
更新
以这种方式编写数字的技巧是以二进制形式查看n
。 23是10111 2 ,或者我们可以写出地方值23 = 1*16 + 0*8 + 1*4 + 1*2 + 1*1
。
这意味着x^23 = x^(16 + 4 + 2 + 1)
并且由于指数法则,= x^16 * x^4 * x^2 * x^1
这就是我们开始的目标。
另一个简单示例:取x^44
。我们用二进制写为101100 2 ,所以我们可以说
44 = 1*32 + 0*16 + 1*8 + 1*4 + 0*2 + 0*1 = 32 + 8 + 4
所以
x^44 = x^(32 + 8 + 4) = x^32 * x^8 * x^4
然后我们计算以下
1: x^2 = (x)^2 (from the x we are given)
2: x^4 = (x^2)^2 (x^2 from step 1)
3: x^8 = (x^4)^2 (x^4 from step 2)
4: x^16 = (x^8)^2 (x^8 from step 3)
5: x^32 = (x^16)^2 (x^16 from step 4)
6: x^44 = (x^32) * (x^8) * (x^4) (using results of steps 2, 3, and 5)
答案 2 :(得分:1)
如你所说,foo
递归地工作。你为什么不一步一步地完成它?假设您a==2
和b==3
第一步
int foo ( int x , int n) // x == 2, n==3
{
int val=1;
if(n>0) // n == 3, true!
{
if (n%2 == 1) //true!
val = val *x; // val = 1 * 2;
val = val * foo(x*x , n/2); // next step
}
return val;
}
第二步
int foo ( int x , int n) // x == 4, n==1
{
int val=1;
if(n>0) // n == 1, true!
{
if (n%2 == 1) //true
val = val *x; val = 1 * 4;
val = val * foo(x*x , n/2); // next step -> 4 * ...
}
return val;
}
在第二步中,返回4,在第一步中产生
val = val * foo(x*x , n/2); // 2 * 4 in the first step and this equals 8