12

Strange things happen when i try to find the cube root of a number.

The following code returns me undefined. In cmd : -1.#IND

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

While this one works perfectly fine. In cmd : 4.93242414866094

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

From mathematical way it must work since we can have the cube root from a negative number. Pow is from Visual C++ 2010 math.h library. Any ideas?

ilcredo
  • 785
  • 2
  • 7
  • 17

12 Answers12

17

pow(x, y) from <cmath> does NOT work if x is negative and y is non-integral.

This is a limitation of std::pow, as documented in the C standard and on cppreference:

Error handling

  • Errors are reported as specified in math_errhandling
  • If base is finite and negative and exp is finite and non-integer, a domain error occurs and a range error may occur.
  • If base is zero and exp is zero, a domain error may occur.
  • If base is zero and exp is negative, a domain error or a pole error may occur.

There are a couple ways around this limitation:

  • Cube-rooting is the same as taking something to the 1/3 power, so you could do std::pow(x, 1/3.).

  • In C++11, you can use std::cbrt. C++11 introduced both square-root and cube-root functions, but no generic n-th root function that overcomes the limitations of std::pow.

wkl
  • 77,184
  • 16
  • 165
  • 176
  • i didn't knew this. since there is no n-th root function in cmath i've improvised. – ilcredo Nov 24 '10 at 16:49
  • 1
    Funny that this accepted answer precisely explains why the "workaround" will not work ! –  Apr 29 '17 at 14:44
8

The power 1/3 is a special case. In general, non-integral powers of negative numbers are complex. It wouldn't be practical for pow to check for special cases like integer roots, and besides, 1/3 as a double is not exactly 1/3!

I don't know about the visual C++ pow, but my man page says under errors:

EDOM The argument x is negative and y is not an integral value. This would result in a complex number.

You'll have to use a more specialized cube root function if you want cube roots of negative numbers - or cut corners and take absolute value, then take cube root, then multiply the sign back on.

Note that depending on context, a negative number x to the 1/3 power is not necessarily the negative cube root you're expecting. It could just as easily be the first complex root, x^(1/3) * e^(pi*i/3). This is the convention mathematica uses; it's also reasonable to just say it's undefined.

Cascabel
  • 479,068
  • 72
  • 370
  • 318
7

While (-1)^3 = -1, you can't simply take a rational power of a negative number and expect a real response. This is because there are other solutions to this rational exponent that are imaginary in nature.
http://www.wolframalpha.com/input/?i=x^(1/3),+x+from+-5+to+0

Similarily, plot x^x. For x = -1/3, this should have a solution. However, this function is deemed undefined in R for x < 0.

Therefore, don't expect math.h to do magic that would make it inefficient, just change the signs yourself.

Vlad
  • 35,022
  • 6
  • 77
  • 199
buddhabrot
  • 1,558
  • 9
  • 14
  • well, it's a function which must have values both negative and positive. I'll put a if for this. – ilcredo Nov 24 '10 at 16:42
3

Guess you gotta take the negative out and put it in afterwards. You can have a wrapper do this for you if you really want to.

function yourPow(double x, double y)
{
    if (x < 0)
        return -1.0 * pow(-1.0*x, y);
    else
        return pow(x, y);
}
jon_darkstar
  • 16,398
  • 7
  • 29
  • 37
  • 1
    Isn't this known as performing a cut along the line x<0? – David Heffernan Nov 24 '10 at 16:38
  • @DavidHeffernan, yes, it does, according to http://mathworld.wolfram.com/CubeRoot.html we have "However, extension of the cube root into the complex plane gives a branch cut along the negative real axis for the principal value of the cube root". – Alessandro Jacopson Sep 09 '13 at 16:59
2

C++11 has the cbrt function (see for example http://en.cppreference.com/w/cpp/numeric/math/cbrt) so you can write something like

#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;
}

I do not have access to the C++ standard so I do not know how the negative argument is handled... a test on ideone http://ideone.com/bFlXYs seems to confirm that C++ (gcc-4.8.1) extends the cube root with this rule cbrt(x)=-cbrt(-x) when x<0; for this extension you can see http://mathworld.wolfram.com/CubeRoot.html

Alessandro Jacopson
  • 18,047
  • 15
  • 98
  • 153
2

Don't cast to double by using (double), use a double numeric constant instead:

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

Should do the trick!

Also: don't include <math.h> in C++ projects, but use <cmath> instead.

Alternatively, use pow from the <complex> header for the reasons stated by buddhabrot

rubenvb
  • 74,642
  • 33
  • 187
  • 332
2

pow( x, y ) is the same as (i.e. equivalent to) exp( y * log( x ) )

if log(x) is invalid then pow(x,y) is also.

Similarly you cannot perform 0 to the power of anything, although mathematically it should be 0.

CashCow
  • 30,981
  • 5
  • 61
  • 92
1

I was looking for cubit root and found this thread and it occurs to me that the following code might work:

#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;
}
guinny
  • 1,522
  • 10
  • 19
  • 3
    It has been a while but `(sign==true)?return x:return -x;` seriously? Is this valid C/++? Why not go with `return sign ? x : -x;`? The same for `x>=0?sign=true:sign=false;` -> `sign = (x >= 0);`. – Nobody moving away from SE Oct 10 '12 at 09:27
  • `(sign==true)?return x:return -x;` is a syntax error. Nobody's suggestions are cleaner and correct. – Moberg Jun 06 '13 at 09:59
  • The focus of this thread is the algorithm and not c++. I offered a method that works and anybody should understand what I meant. You also understood it, didn't you? – guinny Jun 09 '13 at 19:31
0

because the 1/3 will always return 0 as it will be considered as integer... try with 1.0/3.0... it is what i think but try and implement... and do not forget to declare variables containing 1.0 and 3.0 as double...

karan
  • 8,637
  • 3
  • 41
  • 78
0

Here's a little function I knocked up.

#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;
}

It uses Newton-Raphson to find a cube root.

Sometime Newton -Raphson gets stuck, if the root is very close to 0 then the derivative can get large and it can oscillate. So I've clamped and forced it to restart if that happens. If you need more accuracy you can change the FLT_EPSILONs.

Malcolm McLean
  • 6,258
  • 1
  • 17
  • 18
0

If you ever have no math library you can use this way to compute the cubic root:

cubic root

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;
}

It is derives from the sqrt algorithm below. The idea is that b and x / b / b bigger and smaller from the cubic root of x. So, the average of both lies closer to the cubic root of x.

Square Root And Cubic Root (in 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

In contrast to the square root, last_b_1 and last_b_2 are required in the cubic root because b flickers. You can modify these algorithms to compute the fourth root, fifth root and so on.

Thanks to my math teacher Herr Brenner in 11th grade who told me this algorithm for sqrt.

Performance

I tested it on an Arduino with 16mhz clock frequency:

Community
  • 1
  • 1
User
  • 14,131
  • 2
  • 40
  • 59
  • 1
    your `curt` algorithm is wrong. It should be `(2 * b + x / b / b) / 3` –  Aug 06 '15 at 11:14
  • This is a good suggestion as it improves runtime for small numbers. `x = 12` from 26 to 5 iterations. However, for big numbers: `x = 7e+122` from 161 to 235 iterations. Iterations were equal at `x = 7e+30`. Thanks. – User Oct 04 '15 at 06:53
  • 1
    for a large number X try (i) passing 1 / X into the routine and do 1 / result; (ii) dividing by a known cube number below X and multiplying by the cube root at the end –  Oct 05 '15 at 08:17
0

I think you should not confuse exponentiation with the nth-root of a number. See the good old Wikipedia

Luca Martini
  • 1,434
  • 1
  • 15
  • 35