【问题标题】:Using Recursion to raise a base to its exponent - C++使用递归将基数提高到其指数 - C++
【发布时间】:2012-02-19 11:59:28
【问题描述】:

我只是想编写一些代码,利用函数递归来提高基础。我知道递归不是在 C++ 中做事的最正确方法,但我只是想稍微探索一下这个概念。该程序要求用户提供一个基数和一个指数,然后控制台输出答案。这是我编写的程序:

#include <iostream>
#include <math.h>
using namespace std;

int raisingTo(int, int);
int main()
{
    int base, exponent;
    cout << "Enter base value: ";
    cin >> base;
    cout << "Enter exponent value: ";
    cin >> exponent;
    int answer = raisingTo(base, exponent);
    cout << "The answer is: " << answer << endl;
    char response;
    cin >> response;
    return 0;
}

int raisingTo(int base, int exponent)
{
    if (exponent > 0)
        return 1;
    else if (exponent = 0)
    {
        int answer = (int) pow((double)base, raisingTo(base, (exponent - 1)));
        return answer;
    }
}

有趣的是,当我运行这个程序时,它一直返回答案为“1”!有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: c++ recursion pow


    【解决方案1】:
    int raisingTo(int base, unsigned int exponent)
    {
        if (exponent == 0)
            return 1;
        else
            return base * raisingTo(base, exponent - 1);
    }
    

    你有 3 个主要问题:

    • 您不必使用 pow 函数
    • 要比较数字,您应该使用==,因为= 是分配而不是比较。
    • 你错过了如果指数等于 0 你应该返回 1。

    【讨论】:

    • 您能解释一下每个值是如何返回的以及它们是如何累积的吗?你能告诉我为什么你用 raiseTo() 函数乘以基数吗?我只是一个初学者,我真的不明白我在网上找到的参考资料!
    • 我们使用等式:x^n = x * x^(n-1) 这对所有实数都是正确的。以便我们使用它来创建递归函数。递归的底部是指数== 0时。例如2^4 = 2 * 2^32^3 = 2 * 2^2; 2^2 = 2 * 2^1; 2^1 = 2 * 2^02^0 = 1.
    【解决方案2】:

    要使这成为一个实际的 C++ 答案 - 这是您可以考虑将其作为模板函数的任务,因为它适用于任何类型的数字类型。

    递归实际上是个好主意,但前提是你要利用它可以提供的好处:它可以通过从指数中分解出小数来避免一些乘法。 p>

    template <typename NumT>
    NumT raiseTo(NumT base, unsigned exponent) {
      if (exponent == 1) return base;
      if (exponent == 0) return 1;
      if (exponent%2 == 0) { NumT ressqrt = raiseTo(base,exponent/2)
                           ; return ressqrt*ressqrt;                  }
      if (exponent%3 == 0) { NumT rescubrt = raiseTo(base,exponent/3)
                           ; return rescubrt*rescubrt*rescubrt;       }
      else return base * raiseTo(base, --exponent);
    }
    

    这可以节省多少计算的示例:假设您想将一个数字提高到 19。如果您使用朴素的循环式方法,那就是 18 次乘法。有了这个解决方案,会发生什么

    • 19 不能被 2 或 3 整除,因此计算 bbe-1 ,即
    • b18。现在 18 可以被 2 整除,所以我们将 be/2 平方,即
    • b9。其中 9 可以被 3 整除,所以我们立方 be/3,即
    • b3。其中 3 可以被 3 整除,所以我们立方 be/3,即
    • b1,即b。

    这只是 1+1+2+2 = 6 次乘法,是循环式方法所需数量的 1/3!但是,请注意,这并不一定意味着代码会执行得更快,因为检查因素也需要一些时间。特别是,unsigneds 上的%3 可能并不比ints 上的乘法快,所以对于NumT==int,它一点也不聪明。但是对于更昂贵的浮点类型complex,它聪明的,更不用说乘法可能非常昂贵的线性代数矩阵类型了。

    【讨论】:

    • 为什么c++答案必须使用模板? C++ 答案应该使用 OO 而不是 OB
    • @Ulterior:幸运的是,C++不是纯粹的面向对象语言。它允许您在适当的时候使用 OO,因为这里绝对没有理由这样做。另一方面,模板简单明了,可以生成最快的编译程序,并且自动尽可能通用。
    • @Pubby:我也想知道这一点。可能应该意味着 OBfuscation,但我认为像这样的简单模板仅适用于 Java 程序员。
    • 非常感谢您的回答,leftaroundabout。我只需要考虑一下您在这里编写的这段代码。我只是想理解它,我只是这门语言的初学者。
    • 嗯,我很确定 % 比所有类型的乘法都更昂贵,如果它甚至被定义的话。另外你不需要它。
    【解决方案3】:

    你的问题在这里

    if (exponent > 0)
        return 1;
    else if (exponent = 0)
    

    首先,您已经反转了条件(如果指数等于 0,它应该返回),其次,您正在分配而不是与第二个 if 比较。

    【讨论】:

    • int answer = (int) pow((double)base, raisingTo(base, (exponent - 1))); 的行也坏了。
    • else if (exponent = 0) 是一个非常粗鲁的错误!因为它是赋值并且这个操作的结果在这种情况下是右手边的值0所以这个 else if 部分永远不会被执行。为了比较,应该使用==
    • @Seagull:苏?他提到了这一点。
    • 感谢 Seagull 指出我的错误。这是一个简单的错字,我应该写出“==”,因为它毕竟是比较运算符。无论如何,非常感谢您的回答 Necrolis。
    【解决方案4】:

    这是一个复杂度更高的版本(O(lg exponent),而不是 O(exponent)),它在概念上类似于 leftroundabout 的版本。

    int raisingTo(int base const, unsigned int const exponent, int scalar = 1)
    {
        if (exponent == 0)
            return scalar;
    
        if (exponent & 1) scalar *= base;
        return raisingTo(base * base, exponent >> 1, scalar);
    }
    

    它还使用尾递归,这通常会导致更好的优化机器代码。

    【讨论】:

    • 普通的 C 编译器真的可以从尾递归中获得很大的改进吗?不知道,我认为 C-- 的发明主要是因为他们没有。
    • @leftaroundabout:一些现代编译器确实将尾递归优化到迭代中,这是一个可观的节省,同时也避免了潜在的堆栈溢出。然而,标准并不要求它,所以我想要这个改进的复杂性算法的迭代版本,除了问题需要递归。
    【解决方案5】:

    这里有一个更简洁的解释,复杂度为 O(log n)

    public int fastPower(int base , int power){
    
    if ( power==0 )
      return 1 
    else if(power %2 == 0 )
      return fastPower(base*base,power/2)
    else
     return base * fastPower(base,power-1)
    }
    

    这个算法遵循简单的指数规则

    base^0 = 1
    base^power = base*base^(power-1)
    base^(2*power) = (base^2)^power
    

    因此,在每个级别, n 的值要么是原来的一半,要么略小于 n 。因此,递归将最糟糕的是1+log nlevels

    信息source

    【讨论】:

      猜你喜欢
      • 2012-02-22
      • 1970-01-01
      • 1970-01-01
      • 2010-10-02
      • 2021-05-10
      • 2014-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多