2009-09-01 39 views
14

¿Alguien me puede ayudar a encontrar una solución sobre cómo calcular una raíz cúbica del número negativo usando python?Raíz cúbica del número negativo en python

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

no funciona. La raíz cúbica del número negativo es número negativo. Alguna solución?

+3

Como nota al margen: 'float (1)' se escribe más convenientemente como "1.". O puede usar 'desde __future__ división de importación 'y dejar de preocuparse por la división de enteros (1/3 devuelve 0.3333 ...). – EOL

+2

Si solo quiere la raíz real del cubo e ignora las complejas raíces del cubo, dígalo en su pregunta. –

+0

Tenga en cuenta que no hay un número de coma flotante que represente exactamente 1/3, por lo que al usar funciones matemáticas como 'math.pow()' no hay forma de especificar la raíz del cubo. –

Respuesta

10

que puede usar:

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

o más en general:

if x > 0: 
    return math.pow(x, float(1)/3) 
elif x < 0: 
    return -math.pow(abs(x), float(1)/3) 
else: 
    return 0 
+1

Incluso más generalmente, podría hacer que la condición <0 en su lugar sea "x% 2 == 1" y luego definirla como una función que podría tomar un valor N para la raíz en lugar de una codificación 3. 3. – Amber

+0

solo una nota Si está codificando '1/3', no necesita un caso especial para cero. – SilentGhost

+4

En realidad, no necesita un caso especial para el período cero, independientemente de cuál sea la potencia. – Amber

0

solución primitiva:

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

Probablemente masivamente no Pythonic, pero debería funcionar.

10
math.pow(abs(x),float(1)/3) * (1,-1)[x<0] 
+8

"(1, -1) [x <0]" es una expresión que me hace amar y odiar Python al mismo tiempo ;-) –

+0

jaja, sé exactamente lo que quieres decir, pero quería ver si podía conseguir esto en una linea – David

+8

¿Qué pasa con python2.5 y posterior estilo '* (1 si x> 0 else -1)' – u0b34a0f6ae

8

Tomando las respuestas anteriores y haciéndolo en una sola línea:

import math 
def cubic_root(x): 
    return math.copysign(math.pow(abs(x), 1.0/3.0), x) 
+2

¿por qué está convirtiendo 'x' en' flotar'? – SilentGhost

+0

+1 para copysign (nueva función 2.6 ordenada! -) pero de hecho no hay necesidad de esas llamadas float(). –

+0

Estaba confundido por la documentación copysign y pensé que el parámetro tenía que ser flotante. Sin embargo, los enteros funcionan (acabo de probarlo) por lo que no es necesario el reparto. He editado la respuesta. – user9876

3

También puede incluir la biblioteca libm que ofrece una función cbrt (raíz cúbica):

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

da el esperado

-2.0 
+6

Lo que sacrifica la funcionalidad multiplataforma de algo que puede implementarse fácilmente en Python puro. –

+3

Por otro lado, tiene las virtudes de computar la raíz cúbica (en lugar de 0.33333333333333331482961625624739099 ... rd power, que es la razón por la cual el OP se topó con el problema para empezar) y ser más preciso y más rápido en algunas plataformas . Si no necesita portabilidad, esta puede ser una solución muy práctica. –

3

La raíz cúbica de un número negativo es solo el negativo de la raíz cúbica del valor absoluto de ese número.

es decir, x^(1/3) para x < 0 es lo mismo que (-1) * (| x |)^(1/3)

Simplemente haga su número positivo, y luego realizar cúbico raíz.

18

Un uso simple de De Moivre's formula, es suficiente para mostrar que la raíz cúbica de un valor, independientemente del signo, es una función con múltiples valores. Eso significa que, para cualquier valor de entrada, habrá tres soluciones. La mayoría de las soluciones presentadas hasta ahora solo devuelven la raíz principal. A continuación, se muestra una solución que devuelve todas las raíces válidas y pruebas explícitas para casos especiales no complejos.

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) ] 

Editar: a lo solicitado, en los casos en que no es apropiado tener dependencia de numpy, el código siguiente hace lo mismo.

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 ] 
+0

'arg' no se debe dividir por' 3': 'numpy.exp (1j * (arg + 2 * n * math.pi/3))'. También puede usar 'math.cos + 1j * math.sin' si desea deshacerse de la dependencia de numpy. –

+0

Lo recordé correctamente de mi clase de matemática. Entonces la respuesta actualmente aceptada es, entonces, incompleta. –

+0

@MizardX - se requiere la división por tres, forma el denominador del argumento. Ver http://en.wikipedia.org/wiki/De_Moivre%27s_formula#Applications –

9

Puede obtener la completa (todas las raíces n) y más general (ninguna señal, ningún poder) solución usando:

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)] 

Explicación: una es usando la ecuación x u = exp (u * log (x)). Esta solución será entonces una de las raíces, y para obtener las otras, rotarla en el plano complejo en una (rotación completa)/t.

0

Puede utilizar cbrt de scipy.special:

>>> from scipy.special import cbrt 
>>> cbrt(-3) 
-1.4422495703074083 

Esto también funciona para las matrices.

0

Acabo de tener un problema muy similar y encontré la solución NumPy de this forum post.

En una descripción, podemos utilizar los métodos NumPy sign y absolute para ayudarnos. Aquí está un ejemplo que ha trabajado para mí:

import numpy as np 

x = np.array([-81,25]) 
print x 
#>>> [-81 25] 

xRoot5 = np.sign(x) * np.absolute(x)**(1.0/5.0)  
print xRoot5 
#>>> [-2.40822469 1.90365394] 

print xRoot5**5 
#>>> [-81. 25.] 

Así que volviendo a la raíz del problema cubo original:

import numpy as np 

y = -3. 
np.sign(y) * np.absolute(y)**(1./3.) 
#>>> -1.4422495703074083 

espero que esto ayude.

0

Para una aritmética, respuesta calculadora-como en Python 3:

>>> -3.0**(1/3) 
-1.4422495703074083 

o -3.0**(1./3) en Python 2.

Para la solución algebraica de x**3 + (0*x**2 + 0*x) + 3 = 0 uso numpy:

>>> p = [1,0,0,3] 
>>> numpy.roots(p) 
[-3.0+0.j   1.5+2.59807621j 1.5-2.59807621j] 
1

este también funciona con numpy array:

cbrt = lambda n: n/abs(n)*abs(n)**(1./3) 
+0

¿por qué no '(abs (n) * n) * (abs (n) ** (1./3))'? Tiendo a evitar la división por motivos de rendimiento. –

+1

@Salixalba: ¿En serio? En Python, dudo que veas una diferencia de rendimiento significativa entre la división y la multiplicación de flotadores. (Además, su sugerencia calcula 'n ** 2' veces la raíz del cubo, no la raíz del cubo). –

Cuestiones relacionadas