递归"权力"功能

时间:2015-01-21 00:09:55

标签: java recursion

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

http://i.imgur.com/sRoQJ1j.png

我似乎无法做到这一点,因为我在过去的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的操作来平衡最终结果 - 但这只会给我一个巨大的数字。

感谢任何帮助,谢谢。

3 个答案:

答案 0 :(得分:1)

问题出在这句话中:

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)(@rgettman的版本)

使用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算法(因为它主要是尾递归

public static double power(double x, int n) {
    double s = 1.0d;
    while(n != 0) {
        if((n&0x01) != 0x00) {
            s *= x;
        }
        n >>>= 0x01;
        x *= x;
    }
    return s;
}

<强>性能

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

  • power1 @rgettman的版本;
  • power2此答案中提出的递归版本;和
  • power3非递归版本。

如果有人将L设置为10'000'000(因此计算所有权力从0L),则一次运行会导致:

           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以纳秒为单位测量,但这些数字非常不准确,并且与副事件(如OS调用,缓存故障......等)有关,而不是与实际程序运行时有关。

答案 1 :(得分:1)

在“偶数”情况下,您可以使用递归调用计算它,并按照您的方式传递n/2。但是你需要将结果与自身相乘以对其进行平方。

double value = power(x, n/2);
value *= value;
return value;

在“奇数”情况下,您可以将x乘以指数减去1的递归调用。

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

答案 2 :(得分:0)

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

你只需要这个:

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