Calculating cubic root for negative number

You can use this snippet to calculate it. It also works for other powers, e.g. 1/4, 1/5, etc.

function nthroot(x, n) {
  try {
    var negate = n % 2 == 1 && x < 0;
    if(negate)
      x = -x;
    var possible = Math.pow(x, 1 / n);
    n = Math.pow(possible, n);
    if(Math.abs(x - n) < 1 && (x > 0 == n > 0))
      return negate ? -possible : possible;
  } catch(e){}
}

nthroot(-8, 3);

Source: http://gotochriswest.com/blog/2011/05/06/cube-root-an-beyond/

A faster approach for just calculating the cubic root:

Math.cbrt = function(x) {
    var sign = x === 0 ? 0 : x > 0 ? 1 : -1;

    return sign * Math.pow(Math.abs(x), 1 / 3);
}

Math.cbrt(-8);

Update

To find an integer based cubic root, you can use the following function, inspired by this answer:

// positive-only cubic root approximation
function cbrt(n)
{
    var a = n; // note: this is a non optimized assumption

    while (a * a * a > n) {
        a = Math.floor((2 * a + (n / (a * a))) / 3);
    }

    return a;
}

It starts with an assumption that converges to the closest integer a for which a^3 <= n. This function can be adjusted in the same way to support a negative base.


I like the other answers, but how about overriding Math.pow so it would be able to work with all nth roots of negative numbers:

//keep the original method for proxying
Math.pow_ = Math.pow;

//redefine the method
Math.pow = function(_base, _exponent) {
  if (_base < 0) {
    if (Math.abs(_exponent) < 1) {
      //we're calculating nth root of _base, where n === 1/_exponent
      if (1 / _exponent % 2 === 0) {
        //nth root of a negative number is imaginary when n is even, we could return
        //a string like "123i" but this would completely mess up further computation
        return NaN;
      }/*else if (1 / _exponent % 2 !== 0)*/
      //nth root of a negative number when n is odd
      return -Math.pow_(Math.abs(_base), _exponent);
    }
  }/*else if (_base >=0)*/
  //run the original method, nothing will go wrong
  return Math.pow_(_base, _exponent);
};

Fiddled with some test cases, give me a shout if you spot a bug!


Two key problems:

  1. Mathematically, there are multiple cubic roots of a negative number: -2, but also 2 complex roots (see cube roots of unity).
  2. Javascript's Math object (and most other standard math libraries) will not do fractional powers of negative numbers. It converts the fractional power to a float before the function receives it, so you are asking the function to compute a floating point power of a negative number, which may or may not have a real solution. So it does the pragmatic thing and refuses to attempt to calculate such a value.

If you want to get the correct answer, you'll need to decide how mathematically correct you want to be, and write those rules into a non-standard implementation of pow.

All library functions are limited to avoid excessive calculation times and unnecessary complexity.


There's no bug; you are raising a negative number to a fractional power; hence, the NaN.

The top hit on google for this is from Dr Math the explanation is pretty good. It says for for real numbers (not complex numbers anyway), a negative number raised to a fractional power may not be a real number. The simplest example is probably

-4 ^ (1/2)

which is essentially computing the square root of -4. Even though the cubic root of -8 does have real solutions, I think that most software libraries find it more efficient not to do all the complex arithmetic and return NaN only when the imaginary part is nonzero and give you the nice real answer otherwise.

EDIT

Just to make absolutely clear that NaN is the intended result, see the official ECMAScript 5.1 Specification, Section 15.8.2.13. It says:

If x<0 and x is finite and y is finite and y is not an integer, the result is NaN.

Again, even though SOME instances of raising negative numbers to fractional powers have exactly one real root, many languages just do the NaN thing for all cases of negative numbers to fractional roots.

Please do not think JavaScript is the only such language. C++ does the same thing:

If x is finite negative and y is finite but not an integer value, it causes a domain error.