Java 递归的;权力;功能

Java 递归的;权力;功能,java,recursion,Java,Recursion,我们得到了一个用于求解递归函数的赋值,该递归函数可以使用以下规则计算数字的幂(拍摄快照): 我似乎不知道该怎么做,因为我已经试了4个小时了。 我的尝试: public static double power(double x, int n) { if(n == 0) { return 1; } // x^n = ( x^n/2 )^ 2 if n > 0 and n is even if(n % 2 == 0) {

我们得到了一个用于求解递归函数的赋值,该递归函数可以使用以下规则计算数字的幂(拍摄快照):

我似乎不知道该怎么做,因为我已经试了4个小时了。 我的尝试:

public static double power(double x, int n) {   
    if(n == 0) {
        return 1;
    }
    //    x^n = ( x^n/2 )^ 2  if n > 0 and n is even
    if(n % 2 == 0) {
        double value = ((x * power(x, n/2)) * x);
        return value;
    } else {
        double value = x * ((x * power(x, n/2)) * x);
        return value;       
    }
}
当我用递归函数乘以x时,我认为我做错了,而我应该乘以x(幂=x*x*…x(n))

我还可以在这一声明中看到:

 double value = ((x * power(x, n/2)) * x);
这是错误的,因为我没有平方的价值,但只是乘以它与x。我想我需要先把它存储在一个变量中,然后做一些类似value*value的事情来平方最终结果——但这只会给我一个巨大的数字


感谢您的帮助。

问题在于:

if(n % 2 == 0) {
        double value = ((x * power(x, n/2)) * x);
        return value;
它在语法上(括号不匹配)和语义上(更深层次的递归,不正确)

应将其替换为:

if(n % 2 == 0) {
        double value = power(x*x, n/2);
        return value;
原因是:

x^(2*k)=(x^2)^k

这几乎就是代码中实现的内容。因为我们知道
n
是偶数,所以有一个
k=n/2
,这样上面的方程成立

奇数情况也是如此:

else {
        double value = x * power(x*x, n/2);
        return value;
这是因为:

x^(2*k+1)=x*x^(2*k)(@rgetman版本)

使用
k=(n-1)/2
,可进一步优化:

x^(2*k+1)=x*x^(2*k)=x*(x^2)^k(我们的版本)

您可以通过以下方式对此进行进一步优化:

public static double power(double x, int n) {   
    if(n == 0) {
        return 1;
    }
    double xb = x*x;
    if((n&0x01) == 0x00) {
        return power(xb,n>>>0x01);
    } else {
        return x*power(xb,n>>>0x01);
    }
}
或者,您可以将递归方面转换为
while
算法(因为它主要是尾部递归:

性能

实现了三个不同的版本。这显示了基准测试。使用:

  • power1
    @rgetman的版本
  • power2
    此答案中建议的递归版本;以及
  • power3
    非递归版本
如果将
L
设置为
10'000'000
(从而计算
0
L
的所有功率),则一次运行结果为:

           L = 10M           L=20M
power1: 1s 630 018 699     3s 276 492 791
power2: 1s 396 461 817     2s 944 427 704
power3: 0s 803 645 986     2s 453 738 241
不要把逗号后的数字看得太重。虽然Java的测量单位是纳秒,但这些数字非常不准确,而且与副事件(如操作系统调用、缓存故障等)的关系比与实际程序运行时的关系更大。

在“偶数”中在这种情况下,您可以使用递归调用来计算它,如您所做的那样传递
n/2
。但是您需要将结果与自身相乘以将其平方

double value = power(x, n/2);
value *= value;
return value;
在“奇数”情况下,可以通过递归调用指数减去
1
来乘以
x

double value = x * (power(x, n - 1));
return value;

您需要了解递归如何在内部工作。逻辑很简单,就是将函数调用和返回值存储在堆栈中。当达到方法终止条件时,弹出值并从方法返回

你只需要这样:

public static double power(double x, int n) {   
    if(n == 0) {
        return 1;
    } else {
        double value = (x * power(x, (n-1)));
        return value;
    }
}

在奇数情况下执行除法可能更好,因为这会显著减少调用数…@CommuSoft它可能会在此处或此处保存调用,但当我的下一个递归调用发生时,它将是偶数,并且也将在那里执行除法。因此,即使在下一个递归调用中,也会发生除法。我认为在avera中在ge的情况下,调用的数量将减少25%。事实上,没有引入额外的复杂性。请在投反对票时留下评论。我想从我的错误中吸取教训。@JunedAhson:我没有投反对票,但这种方法的问题是,算法在线性时间内运行,具有强大的能力和能力(如果没有优化的话),以一个巨大的堆栈返回。@CommuSoft谢谢!我试图提供一个简单的解决方案,而不是优化的解决方案。此解决方案是针对提问者的,而不是针对超级编码者。问题要求不涉及算法的复杂性。我亲爱的投票人/优化编码者。此解决方案不适合您。很抱歉冒犯您。不确定哪一个答案我应该接受:(P.S-我有一个脑屁。你能解释一下功率(x*x,n/2)是如何工作的吗?我不明白它是如何工作的,即使你没有给出正确的答案。
public static double power(double x, int n) {   
    if(n == 0) {
        return 1;
    } else {
        double value = (x * power(x, (n-1)));
        return value;
    }
}