tags:

views:

1198

answers:

9

Can someone help me to find solution on how to calculate cubic root of the negative number using python?

>>> math.pow(-3, float(1)/3)
nan

it does not work. Cubic root of the negative number is negative number. Any solutions?

+8  A: 

You could use:

-math.pow(3, float(1)/3)

Or more generally:

if x > 0:
    return math.pow(x, float(1)/3)
elif x < 0:
    return -math.pow(abs(x), float(1)/3)
else:
    return 0
Al
Even more generally, you could make the < 0 condition instead be "x%2 == 1" and then define it instead as a function that could take a value N for the root instead of hard-coding 3.
Amber
just a note, if you're hard-coding `1/3` you don't need a special case for zero.
SilentGhost
Actually, you don't need a special case for zero period, regardless of what the power is.
Amber
huh? `math.pow(0, -2)`
SilentGhost
-1 for not using `math.pow(...) if x... else...`, and also for handling `x==0` as a separate case (math.pow(0, 1./3) is 0).
EOL
@SilentGhost `math.pow(0, -2)` raises an exception, which is much more appropriate than returning 0. I do agree with you, Dav!
EOL
@Dav: I agree that the special case is unnecessary, but it felt a bit daft to me to call math.pow() in order to return a constant. Admittedly, the same could be said for any value, but I was working on the assumption that the power may need to be changed to work with any odd reciprocal.
Al
A: 

Primitive solution:

def cubic_root(nr):
   if nr<0:
     return -math.pow(-nr, float(1)/3)
   else:
     return math.pow(nr, float(1)/3)

Probably massively non-pythonic, but it should work.

Joachim Sauer
+11  A: 
math.pow(abs(x),float(1)/3) * (1,-1)[x<0]
David
"(1,-1)[x<0]" is an expression that makes me love and hate python at the same time ;-)
Joachim Sauer
haha, I know exactly what you mean, but I wanted to see if I could get this into one line.
David
What about python2.5 and later style `* (1 if x > 0 else -1)`
kaizer.se
Oh, golf, is it? You're 3 over par: "math.pow(abs(x),y)*cmp(x,0)"
Alec
I guess that should be "math.pow(abs(x),1./3)*cmp(x,0)", since x<0 y=1/2 would be screwy.
Alec
+5  A: 

Taking the earlier answers and making it into a one-liner:

import math
def cubic_root(x):
    return math.copysign(math.pow(abs(x), 1.0/3.0), x)
user9876
why are you converting `x` to `float`?
SilentGhost
+1 for copysign (neat new 2.6 function!-) but there's indeed no need for those float() calls.
Alex Martelli
I was confused by the copysign documentation and thought the parameter had to be a float. However, integers work (I just tested it) so there's no need for the cast. I've edited the answer.
user9876
+3  A: 

You can also wrap the libm library that offers a cbrt (cube root) function:

from ctypes import *
libm = cdll.LoadLibrary('libm.so.6')
libm.cbrt.restype = c_double
libm.cbrt.argtypes = [c_double]
libm.cbrt(-8.0)

gives the expected

-2.0
Otto Allmendinger
Which sacrifices cross-platform functionality for something that can easily be implemented in pure Python.
Joachim Sauer
On the other hand, it has the virtues of computing the cube root (instead of the 0.33333333333333331482961625624739099...rd power, which is why the OP ran into the problem to start with), and being both more accurate and faster on some platforms. If you don't need portability, this can be a very practical solution.
Stephen Canon
+3  A: 

The cubic root of a negative number is just the negative of the cubic root of the absolute value of that number.

i.e. x^(1/3) for x < 0 is the same as (-1)*(|x|)^(1/3)

Just make your number positive, and then perform cubic root.

Kirk Broadhurst
+12  A: 

A simple use of De Moivre's formula, is sufficient to show that the cube root of a value, regardless of sign, is a multi-valued function. That means, for any input value, there will be three solutions. Most of the solutions presented to far only return the principle root. A solution that returns all valid roots, and explicitly tests for non-complex special cases, is shown below.

import numpy
import math
def cuberoot( z ):
    z = complex(z)
    x = z.real
    y = z.imag
    mag = abs(z)
    arg = math.atan2(y,x)
    return [ mag**(1./3) * numpy.exp( 1j*(arg+2*n*math.pi)/3 ) for n in range(1,4) ]

Edit: As requested, in cases where it is inappropriate to have dependency on numpy, the following code does the same thing.

def cuberoot( z ):
    z = complex(z) 
    x = z.real
    y = z.imag
    mag = abs(z)
    arg = math.atan2(y,x)
    resMag = mag**(1./3)
    resArg = [ (arg+2*math.pi*n)/3. for n in range(1,4) ]
    return [  resMag*(math.cos(a) + math.sin(a)*1j) for a in resArg ]
Andrew Walker
`arg` shouldn't be divided by `3`: `numpy.exp( 1j*(arg+2*n*math.pi/3) )`.You could also use `math.cos+1j*math.sin` if you want to get rid of the dependency on numpy.
MizardX
I did recall correctly from my math class. So the currently accepted answer is, then, incomplete.
sheepsimulator
@MizardX - the division by three is required, it forms the denominator of the argument. See http://en.wikipedia.org/wiki/De_Moivre%27s_formula#Applications
Andrew Walker
+6  A: 

You can get the complete (all n roots) and more general (any sign, any power) solution using:

import cmath

x, t = -3., 3  # x**(1/t)

a = cmath.exp((1./t)*cmath.log(x))
p = cmath.exp(1j*2*cmath.pi*(1./t))

r = [a*(p**i) for i in range(t)]

Explanation: a is using the equation xu = exp(u*log(x)). This solution will then be one of the roots, and to get the others, rotate it in the complex plane by a (full rotation)/t.

tom10
A: 

Maybe math.pow is the problem:

(Using Python 2.5.4)
>>> -1**(1/3.)
-1.0
Paul McGuire