2009-09-01 2 views
14

Kann mir jemand helfen, eine Lösung zu finden, wie man eine kubische Wurzel der negativen Zahl mit Python berechnet?Kubische Wurzel der negativen Zahl auf Python

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

es funktioniert nicht. Kubische Wurzel der negativen Zahl ist negative Zahl. Irgendwelche Lösungen?

+3

Als Randnotiz: 'float (1)' ist praktischer als "1." geschrieben. Oder Sie können 'from __future__ import division' verwenden und aufhören, sich Gedanken über die Ganzzahldivision zu machen (1/3 gibt 0.3333 zurück ...). – EOL

+2

Wenn Sie nur die echte Kubikwurzel möchten und die komplexen Kubikwurzeln ignorieren möchten, sagen Sie dies bitte in Ihrer Frage. –

+0

Beachten Sie, dass es keine Gleitkommazahl gibt, die 1/3 genau darstellt. Daher können Sie mathematische Funktionen wie 'math.pow()' nicht verwenden, um die Kubikwurzel anzugeben. –

Antwort

10

könnten Sie verwenden:

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

Oder allgemeiner:

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

Noch allgemeiner können Sie die Bedingung <0 stattdessen "x% 2 == 1" festlegen und sie stattdessen als eine Funktion definieren, die statt der harten Codierung einen Wert N für die Wurzel annehmen könnte. – Amber

+0

nur eine Anmerkung , wenn Sie '1/3' hart codieren, brauchen Sie keinen speziellen Fall für Null. – SilentGhost

+4

Eigentlich brauchen Sie keinen speziellen Fall für Null-Periode, unabhängig davon, was die Macht ist. – Amber

0

Primitive Lösung:

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

Wahrscheinlich massiv Nicht-pythonic, aber es sollte funktionieren.

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

"(1, -1) [x <0]" ist ein Ausdruck, der mich gleichzeitig Python lieben und hassen lässt ;-) –

+0

haha, ich weiß genau, was du meinst, aber ich wollte sehen, ob ich es schaffen könnte dies in einer Linie. – David

+8

Was ist mit python2.5 und späterem Stil? * (1 wenn x> 0 sonst -1) ' – u0b34a0f6ae

8

die früheren Antworten nehmen und es in einen Einzeiler machen:

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

Warum konvertieren Sie 'x' zu' float'? – SilentGhost

+0

+1 für Copysign (nette neue 2.6 Funktion! -), aber es gibt in der Tat keine Notwendigkeit für diese float() -Aufrufe. –

+0

Ich war durch die Copysign-Dokumentation verwirrt und dachte, der Parameter müsse ein Float sein. Allerdings arbeiten ganze Zahlen (ich habe es gerade getestet), so dass die Besetzung nicht benötigt wird. Ich habe die Antwort bearbeitet. – user9876

3

Sie können auch die libm Bibliothek wickeln, die eine cbrt (Kubikwurzel) Funktion bietet:

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

ergibt das erwartete

-2.0 
+6

Das opfert plattformübergreifende Funktionalität für etwas, das in reinem Python einfach implementiert werden kann. –

+3

Auf der anderen Seite hat es die Vorteile der Berechnung der Kubikwurzel (anstelle der 0.333333333333333331482961625624739099 ... rd Macht, weshalb das OP begann in das Problem zu starten), und sowohl genauer und schneller auf einigen Plattformen . Wenn Sie keine Portabilität benötigen, kann dies eine sehr praktische Lösung sein. –

3

Die Kubikwurzel einer negativen Zahl ist nur das Negativ der Kubikwurzel des absoluten Wertes dieser Zahl.

dh x^(1/3) für x < 0 ist das gleiche wie (-1) * (| x |)^(1/3)

einfach Ihre Zahl positiv machen, und führen Sie dann kubisch Wurzel.

18

Eine einfache Verwendung von De Moivre's formula reicht aus, um zu zeigen, dass die Kubikwurzel eines Werts unabhängig vom Vorzeichen eine mehrwertige Funktion ist. Das heißt, für jeden Eingabewert gibt es drei Lösungen. Die meisten der bisher vorgestellten Lösungen geben nur das Grundprinzip zurück. Eine Lösung, die alle gültigen Wurzeln zurückgibt und explizit auf nicht komplexe Sonderfälle testet, ist unten dargestellt.

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: Wie gewünscht, in Fällen, in denen es nicht angebracht ist, die Abhängigkeit von numpy zu haben, der folgende Code macht das Gleiche.

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' sollte nicht durch' 3' geteilt werden: 'numpy.exp (1j * (arg + 2 * n * math.pi/3))' '. Sie können auch 'math.cos + 1j * math.sin' verwenden, wenn Sie die Abhängigkeit von numpy loswerden wollen. –

+0

Ich habe mich richtig aus meinem Matheunterricht erinnert. Die aktuell angenommene Antwort ist also unvollständig. –

+0

@MizardX - die Division durch drei ist erforderlich, es bildet den Nenner des Arguments. Siehe http://en.wikipedia.org/wiki/De_Moivre%27s_formula#Applications –

9

Sie können die vollständige bekommen (alle n Wurzeln) und allgemeinere (jedes Zeichen, jede Leistung) Lösung mit:

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

Erläuterung: a die Gleichung wird mit x u = exp (u * log (x)). Diese Lösung wird dann eine der Wurzeln sein, und um die anderen zu erhalten, rotieren sie in der komplexen Ebene um eine (volle Rotation)/t.

0

Sie können cbrt von scipy.special verwenden:

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

Diese für Arrays funktioniert auch.

0

Ich hatte gerade ein sehr ähnliches Problem und fand die NumPy-Lösung von .

In einem nushell können wir die NumPy sign und absolute Methoden verwenden, um uns zu helfen. Hier ist ein Beispiel, das für mich gearbeitet hat:

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

So geht zurück auf das ursprüngliche Kubikwurzel Problem:

import numpy as np 

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

Ich hoffe, das hilft.

0

Für eine arithmetische, Rechner-ähnliche Antwort in Python 3:

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

oder -3.0**(1./3) in Python 2.

Für die algebraische Lösung von x**3 + (0*x**2 + 0*x) + 3 = 0 Verwendung numpy:

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

dieses funktioniert auch mit numpy Array:

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

Warum nicht? (Abs (n) * n) * (abs (n) ** (1./3)) '? Aus Performancegründen tendiere ich dazu, eine Teilung zu vermeiden. –

+1

@Salixalba: Ernsthaft? In Python bezweifle ich, dass Sie einen signifikanten Leistungsunterschied zwischen Division und Multiplikation von Floats sehen werden. (Außerdem berechnet Ihr Vorschlag "n ** 2" mal die Kubikwurzel, nicht die Kubikwurzel.) –