在C ++中查找cube root?

时间:2010-11-24 16:27:50

标签: c++ math.h pow

当我试图找到数字的立方根时,会发生奇怪的事情。

以下代码返回undefined undefined。在cmd:-1。#IND

cout<<pow(( double )(20.0*(-3.2) + 30.0),( double )1/3)

虽然这个很好用。在cmd:4.93242414866094

cout<<pow(( double )(20.0*4.5 + 30.0),( double )1/3)

从数学方面来看,它必须有效,因为我们可以从负数中得到立方根。 Pow来自Visual C ++ 2010 math.h库。有什么想法吗?

12 个答案:

答案 0 :(得分:15)

如果x为负数且y为非整数,则来自pow(x, y)的{​​p> <cmath>不起作用。

这是std::pow的限制,如C标准和cppreference中所述:

  

错误处理

     
      
  • 按照math_errhandling
  • 中的规定报告错误   
  • 如果base为有限且为负且exp为有限且非整数,则会发生域错误并可能发生范围错误。
  •   
  • 如果base为零且exp为零,则可能发生域错误。
  •   
  • 如果base为零且exp为负数,则可能会出现域错误或极点错误。
  •   

这种限制有几种方法:

  • 立方体生根与取得1/3功率相同,因此您可以std::pow(x, 1/3.)

  • 在C ++ 11中,您可以使用std::cbrt。 C ++ 11引入了平方根和立方根函数,但没有通用的第n个根函数来克服std::pow的限制。

答案 1 :(得分:8)

权力1/3是一种特殊情况。通常,负数的非整数幂是复杂的。对于pow来检查像整数根这样的特殊情况是不切实际的,此外,1/3作为双精度并不完全是1/3!

我不知道visual C ++ pow,但是我的man page在错误中说:

  

EDOM参数x为负数,y不是整数值。这会导致数字复杂。

如果你想要负数的立方根 - 或者削减角落并取绝对值,你需要使用一个更专业的立方根函数,然后取立方根,然后重新加上符号。

请注意,根据上下文,x幂的负数1/3不一定是您期望的负立方根。它可以很容易地成为第一个复杂的根x^(1/3) * e^(pi*i/3)。这是mathematica使用的惯例;只是说它未定义也是合理的。

答案 2 :(得分:7)

当(-1)^ 3 = -1时,你不能简单地采用负数的理性幂并期望得到真实的反应。这是因为这个理性指数的其他解决方案本质上是虚构的 http://www.wolframalpha.com/input/?i=x^(1/3),+x+from+-5+to+0

同样地,绘制x ^ x。对于x = -1/3,这应该有一个解决方案。但是,对于x

因此,不要指望math.h做一些会使效率低下的魔法,只需自己更改标志。

答案 3 :(得分:3)

猜猜你必须把消极的东西拿出去然后把它放进去。如果您真的想要,可以让包装器为您执行此操作。

function yourPow(double x, double y)
{
    if (x < 0)
        return -1.0 * pow(-1.0*x, y);
    else
        return pow(x, y);
}

答案 4 :(得分:2)

请勿使用double转换为(double),而是使用双倍数字常量:

double thingToCubeRoot = -20.*3.2+30;
cout<< thingToCubeRoot/fabs(thingToCubeRoot) * pow( fabs(thingToCubeRoot), 1./3. );

应该做的伎俩!

另外:不要在C ++项目中包含<math.h>,而是使用<cmath>

或者,根据buddhabrot所述的原因,使用pow标题中的<complex>

答案 5 :(得分:2)

pow( x, y )exp( y * log( x ) )

相同(即相当于){{1}}

如果log(x)无效,那么pow(x,y)也是。

同样地,你不能对任何东西的力量执行0,虽然在数学上它应该是0。

答案 6 :(得分:2)

C ++ 11具有cbrt函数(例如参见http://en.cppreference.com/w/cpp/numeric/math/cbrt),因此您可以编写类似

的内容
#include <iostream>
#include <cmath>

int main(int argc, char* argv[])
{
   const double arg = 20.0*(-3.2) + 30.0;
   std::cout << cbrt(arg) << "\n";
   std::cout << cbrt(-arg) << "\n";
   return 0;
}

我无法访问C ++标准,因此我不知道如何处理否定参数...对ideone http://ideone.com/bFlXYs的测试似乎证实C ++(gcc-4.8.1)扩展了多维数据集在cbrt(x)=-cbrt(-x)时使用此规则的x<0;对于此扩展程序,您可以看到http://mathworld.wolfram.com/CubeRoot.html

答案 7 :(得分:1)

我正在寻找cubit root并找到了这个帖子,我觉得以下代码可能有效:

#include <cmath>
using namespace std;

function double nth-root(double x, double n){
    if (!(n%2) || x<0){
        throw FAILEXCEPTION(); // even root from negative is fail
    }

    bool sign = (x >= 0);

    x = exp(log(abs(x))/n);

    return sign ? x : -x;
}

答案 8 :(得分:0)

我认为你不应该将取幂与数字的第n个根混淆。查看好的旧Wikipedia

答案 9 :(得分:0)

因为1/3将始终返回0,因为它将被视为整数... 试试1.0 / 3.0 ...... 这是我的想法,但尝试和实施...... 并且不要忘记将包含1.0和3.0的变量声明为double ...

答案 10 :(得分:0)

这是我敲了一个小功能。

#define uniform() (rand()/(1.0 + RAND_MAX))

double CBRT(double Z)
{
    double guess = Z;
    double x, dx;
    int loopbreaker;

retry:
    x = guess * guess * guess;
    loopbreaker = 0;
    while (fabs(x - Z) > FLT_EPSILON)
    {
        dx = 3 * guess*guess;
        loopbreaker++;
        if (fabs(dx) < DBL_EPSILON || loopbreaker > 53)
        {
            guess += uniform() * 2 - 1.0;
            goto retry;
        }
        guess -= (x - Z) / dx;
        x = guess*guess*guess;
    }

    return guess;
}

它使用Newton-Raphson来查找立方根。

有时Newton -Raphson会被卡住,如果根非常接近于0那么导数就可以了 变大,它可以振荡。因此,如果发生这种情况,我已将其限制并强制重启。 如果您需要更高的准确度,可以更改FLT_EPSILON。

答案 11 :(得分:0)

如果您没有数学库,可以使用这种方式计算立方根:

立方根

double curt(double x) {
  if (x == 0) {
    // would otherwise return something like 4.257959840008151e-109
    return 0;
  }
  double b = 1; // use any value except 0
  double last_b_1 = 0;
  double last_b_2 = 0;
  while (last_b_1 != b && last_b_2 != b) {
    last_b_1 = b;
    // use (2 * b + x / b / b) / 3 for small numbers, as suggested by  willywonka_dailyblah
    b = (b + x / b / b) / 2;
    last_b_2 = b;
    // use (2 * b + x / b / b) / 3 for small numbers, as suggested by  willywonka_dailyblah
    b = (b + x / b / b) / 2;
  }
  return b;
}

它源自下面的sqrt算法。我们的想法是bx / b / bx的立方根更大更小。因此,两者的平均值更接近x的立方根。

平方根和立方根(在Python中)

def sqrt_2(a):
    if a == 0:
        return 0
    b = 1
    last_b = 0
    while last_b != b:
        last_b = b
        b = (b + a / b) / 2
    return b

def curt_2(a):
    if a == 0:
        return 0
    b = a
    last_b_1 = 0;
    last_b_2 = 0;
    while (last_b_1 != b and last_b_2 != b):
        last_b_1 = b;
        b = (b + a / b / b) / 2;
        last_b_2 = b;
        b = (b + a / b / b) / 2;
    return b

与平方根相比,立方根中需要last_b_1last_b_2,因为b闪烁。您可以修改这些算法以计算第四个根,第五个根等等。

感谢我11年级的数学老师Herr Brenner,他告诉我sqrt的算法。

效果

我在16mhz时钟频率的Arduino上进行了测试: