12

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

以下代码返回我未定义。在 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 库。有任何想法吗?

4

12 回答 12

17

pow(x, y)如果 x 为负且 y 非整数,则from<cmath>不起作用。

这是std::powC 标准和cppreference中记录的 的限制:

错误处理

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

有几种方法可以绕过这个限制:

  • Cube-rooting 和 1/3 次方是一样的,所以你可以做std::pow(x, 1/3.).

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

于 2010-11-24T16:32:52.623 回答
8

电源1/3是一种特殊情况。通常,负数的非整数幂是复数。pow 检查整数根等特殊情况是不切实际的,此外,1/3因为双精度数不完全是 1/3!

我不知道视觉 C++ pow,但我的手册页在错误下说:

EDOM参数x为负数,y不是整数值。这将导致一个复数。

如果您想要负数的立方根,则必须使用更专业的立方根函数 - 或者偷工减料并取绝对值,然后取立方根,然后再乘以符号。

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

于 2010-11-24T16:36:13.897 回答
7

虽然 (-1)^3 = -1,但您不能简单地取负数的有理幂并期望得到真正的响应。这是因为对于这个有理指数还有其他的解决方案,这些解决方案本质上是虚构的。
http://www.wolframalpha.com/input/?i=x^(1/3),+x+from+-5+to+0

同样,绘制 x^x。对于 x = -1/3,这应该有一个解决方案。但是,对于 x < 0,此函数在 R 中被视为未定义。

因此,不要指望 math.h 会做一些会使其效率低下的魔术,只需自己更改符号即可。

于 2010-11-24T16:35:34.287 回答
3

猜猜你得把负片拿出来,然后再放进去。如果你真的想的话,你可以让一个包装器为你做这件事。

function yourPow(double x, double y)
{
    if (x < 0)
        return -1.0 * pow(-1.0*x, y);
    else
        return pow(x, y);
}
于 2010-11-24T16:35:11.313 回答
2

不要double通过 using强制转换为(double),而是使用双数字常量:

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

应该做的伎俩!

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

或者,出于 buddhabrot 所述的原因,pow从标题中使用<complex>

于 2010-11-24T16:34:30.823 回答
2

pow( x, y )与(即等价于)相同exp( y * log( x ) )

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

同样,您不能执行 0 的任何操作,尽管在数学上它应该是 0。

于 2010-11-24T16:52:30.173 回答
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)when x<0; 对于这个扩展,你可以看到http://mathworld.wolfram.com/CubeRoot.html

于 2013-09-09T16:57:51.673 回答
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;
}
于 2012-05-04T00:13:28.187 回答
0

我认为您不应该将求幂与数字的第 n 根混淆。参见古老的维基百科

于 2010-11-24T16:36:59.420 回答
0

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

于 2013-03-05T08:20:21.430 回答
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。

于 2014-02-26T13:54:18.430 回答
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下面的算法。这个想法是,从 的立方根开始越来越b小。因此,两者的平均值更接近 的三次根。x / b / bxx

平方根和立方根(在 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_1并且last_b_2在三次根中需要,因为 b 闪烁。您可以修改这些算法来计算第四根、第五根等。

感谢我 11 年级的数学老师 Herr Brenner 告诉我这个算法sqrt

表现

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

于 2015-02-02T07:42:19.097 回答