我正在尝试编写一个递归函数,以将一个数字升为另一个数字的幂,如果n为偶数或x ^ n = x *(x ^,则x ^ n =(x ^(n / 2)^ 2 (n-1)),如果n为奇数。
我已经考虑了很长时间,并尝试了一些方法 但老实说,我不知道如何解决这个问题,尤其是当n为奇数时。我编写了一些代码,以防n为偶数,但是我什至不知道发布它是否有意义,因为它背后的逻辑本身已经很糟糕了。
任何帮助表示赞赏!
int power(int x, int n){
int result = 1;
if(n % 2 == 0){
n /= 2;
for(; n > 0; n--){
result *= x;
}
power(result, 2);
}
return result;
}
第二次尝试,没有for循环:
int power(int x, int n){
int result = 1;
if(n % 2 == 0){
result *= x;
power(x, n / 2);
}
return result;
}
答案 0 :(得分:2)
这里是使用递归“ x ^ n =(x ^(n / 2)^ 2如果n为偶数,或者x ^ n = x *(x ^(n-1))如果使用n则”的直译:
int power(int x, int n){
int temp;
if(n % 2 == 0){
// n is even
temp = power(x, n / 2);
return temp * temp;
} else {
// n is odd
return x * power(x, n - 1);
}
}
请注意,此代码是有意的错误(可能会“永远”递归并导致堆栈溢出),因为原始说明未包含针对n = 0
情况的特殊处理。
对于更正确/更少文字的版本:
int power(int x, int n){
int temp;
if(n % 2 == 0){
// n is even
if(n == 0) {
return 1;
}
temp = power(x, n / 2);
return temp * temp;
} else {
// n is odd
return x * power(x, n - 1);
}
}
当然(因为可读性,可维护性和性能)这是比较糟糕的,因为要求很糟糕。忽略要求(并且不是递归的)的版本将是:
int power(int x, int n){
int result = 1;
while(n > 0) {
if( (n & 1) != 0) {
result *= x;
}
n >>= 1;
x *= x;
}
return result;
}
主题外的
对于计算能力,如果将指数转换为二进制,则可以使用每个二进制数字作为标志来确定是否将结果与“每次迭代的平方”临时值相乘。例如,x**5
与(x**4) * (x**1)
相同,因为5 == 101b
。
这在需要处理小数指数时非常重要/有用。例如,x**5.5
与(x**4) * (x**1) * (x**0.5)
相同,因为5.5 == 101.1b
。
换句话说,从指数的小数点开始,一直到指数的整数部分的最高有效位,您可以if(next bit of exponent was set) { result *= temp}; temp *= temp;
;然后从指数的小数点开始,一直到指数的小数部分的最低有效位,就可以if(next bit of exponent was set) { result *= temp}; temp = sqrt(temp);
。
当我第一次编写此答案时,最后一个示例代码是使用我在此描述的“将指数转换为二进制数字”方法编写的,而与“ x ^ n =(x ^(n / 2)^”无关2如果n是偶数,或者x ^ n = x *(x ^(n-1))如果n是奇数”,直到后来我才意识到原来问题中的方法最终是不同角度的等效代码。
答案 1 :(得分:1)
在进入代码之前,让我们看看您应该如何评估它,看看我们是否可以更好地理解它。我将使用monospace
进行数学运算,而不是使用C代码来更轻松地区分它:
首先,出于稍后讨论的原因,我需要将您的规则更改为偶数。我将不写(x^(n/2))^2
,而是写squared
。您需要以与其他部分不同的方式处理此部分。除此之外,您问题中^
的每个实例都意味着“我们需要使用相同的算法来计算此功效”。
这意味着您的算法是:
n
是偶数,则x^n = (x^(n/2)) squared
。n
为奇数,则x^n = x*(x^(n-1))
。让我们用一个简单的3^5
示例来看看它是如何进行的。如果将其扩展,则由于5
是奇数,因此最终会得到3 * (3^4)
。您仍然不知道3^4
是什么,因此您需要使用相同的算法再次将其扩展。由于4
是偶数,因此将其计算为(3^2) squared
,因此3^5
的完整值为3 * ((3^2) squared)
。同样,我们使用相同的算法评估^
;因为2
也是偶数,所以它变成3 * ((3^1 squared) squared)
。这也有一个^
;所以我们做同样的事情:使用上面的算法。由于1
是奇数,因此变成3 * (((3 * 3^0) squared) squared)
。
现在,0
是偶数,但是一旦您进入3^0
,继续尝试使用较小的功率就没有意义了。由于0/2
是0
,因此您将回到起点,尝试再次评估3^0
。因此,0
需要作为特殊情况进行处理。这为算法添加了第三条规则:
n
是0
,则x^n = 1
。在代码中,您需要先检查此项,然后再检查“如果n
是偶数”规则,因为0
是偶数,我们要先运行此检查。每个递归算法都有至少一个这样的特殊情况,有时甚至更多。术语是基本情况。¹
现在我们有了处理x^0
的规则,我们可以继续查找3^5
。我们的最后一步是3 * (((3 * 3^0) squared) squared)
。使用我们的x^0
规则,它变成3 * (((3 * 1) squared) squared)
。由于此表达式中不再包含^
,因此我们已完成递归。现在我们只需要计算结果:3 * ((3 squared) squared)
。您仍然需要不使用此squared
操作来解决^
,但是由于指数是固定的,您可以将其写为乘法。如果这样做,您将得到3 * (9 squared)
,然后是3 * 81
,然后是243
,这是我们的最终答案。
在评论中,您问“函数如何知道幂表示乘以n乘以基数”。答案是“我们计算了3*1
,然后对结果求平方两次,然后再乘以3。这就是所有乘法的结果:有些是3
的完全乘法,并且是平方有效的乘法运算次数增加了一倍。”
¹递归的标准示例是阶乘(n! = n * (n-1)!
和斐波那契数(F(n) = F(n-1) + F(n - 2)
)。对于阶乘,基本情况为0! = 1
,对于斐波那契数,有两个基本情况, F(0) = 0
和F(1) = 1
。
一些松散的结局:
3^2
处的无限循环。如果我们在不改变偶数规则的情况下进行评估,则会得到(3^1)^2
。如我们所见,3^1
是3
,所以我们将回到3^2
。这告诉我们3^2
等于3^2
,这是正确的,但没有用。另一种选择是使n = 2
之后的n = 0
成为另一种基本情况,但是这种方式更简洁。squared
而不是^2
来处理偶数之后,最终算法是:
n
是0
,则x^n = 1
。n
是偶数,则x^n = (x^(n/2)) squared
。n
是奇数,所以x^n = x*(x^(n-1))
。power(3, 5)
执行return 3 * power(3, 4);
。power(3, 4)
执行temp = power(3, 2);
。power(3, 2)
执行temp = power(3, 1);
。power(3, 1)
执行return 3 * power(3, 0);
。power(3, 0)
返回1
到power(3, 1)
。power(3, 1)
计算3 * 1
并将3
返回到power(3, 2)
。power(3, 2)
执行return temp * temp
,评估3 * 3
,然后将9
返回到power(3, 4)
。power(3, 4)
执行return temp * temp
,评估9 * 9
,然后将81
返回到power(3, 5)
。power(3, 5)
计算3 * 81
并返回243
。**
用于求幂而不是^
,因为^
意味着其他含义(按位xor)。答案 2 :(得分:0)
#include <stdio.h>
int power(int n1, int n2);
int main()
{
int base, powerRaised, result;
printf("Enter base number: ");
scanf("%d",&base);
printf("Enter power number(positive integer): ");
scanf("%d",&powerRaised);
result = power(base, powerRaised);
printf("%d^%d = %d", base, powerRaised, result);
return 0;
}
int power(int base, int powerRaised)
{
if (powerRaised != 0)
return (base*power(base, powerRaised-1));
else
return 1;
}