2009-09-01 13 views
14

Czy ktoś może mi pomóc znaleźć rozwiązanie, w jaki sposób obliczyć sześcienny korzeń z liczby ujemnej za pomocą python?Korzeń sześcienny liczby ujemnej na pytonie

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

to nie działa. Korzeń sześcienny liczby ujemnej jest liczbą ujemną. Jakieś rozwiązania?

+3

Na marginesie: "float (1)" jest wygodniej napisane jako "1.". Lub możesz użyć 'from __future__ import division' i przestań się martwić o dzielenie liczby całkowitej (1/3 zwraca 0.3333 ...). – EOL

+2

Jeśli potrzebujesz tylko prawdziwego pierwiastka kostki i zignorujesz złożone korzenie sześcianu, powiedz to w swoim pytaniu. –

+0

Należy pamiętać, że nie ma liczby zmiennoprzecinkowej, która reprezentuje dokładnie 1/3, więc używając funkcji matematycznych takich jak 'math.pow()' nie ma możliwości określenia korzenia kostki. –

Odpowiedz

10

Można użyć:

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

lub bardziej ogólnie:

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

Nawet bardziej ogólnie, można zamiast tego ustawić warunek <0 "x% 2 == 1", a następnie zdefiniować go jako funkcję, która może przyjąć wartość N dla korzenia zamiast twardego kodowania 3. – Amber

+0

po prostu notatka , jeśli ciężko kodujesz "1/3", nie potrzebujesz specjalnego przypadku dla zera. – SilentGhost

+4

W rzeczywistości, nie potrzebujesz specjalnego przypadku na okres zerowy, niezależnie od mocy. – Amber

0

Primitive rozwiązanie:

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

Prawdopodobnie masowo nie pythonic, ale powinno działać.

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

"(1, -1) [x <0]" to wyrażenie, które sprawia, że ​​kocham i nienawidzę pytona w tym samym czasie ;-) –

+0

haha, wiem dokładnie, co masz na myśli, ale chciałem zobaczyć, czy mogę dostać to w jedną linię. – David

+8

Co z python2.5 i nowszym stylem '* (1 jeśli x> 0 else -1)' – u0b34a0f6ae

8

Biorąc wcześniejsze odpowiedzi i uczynienie go w jednej wkładki:

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

dlaczego konwertujesz 'x' na' float'? – SilentGhost

+0

+1 dla copysign (nowa funkcja 2.6! -), ale nie ma potrzeby wykonywania tych wywołań funkcji float(). –

+0

Byłem zdezorientowany przez dokumentację copysign i myślałem, że parametr musiał być zmiennoprzecinkowy. Jednakże, liczby całkowite działają (właśnie to przetestowałem), więc nie ma potrzeby obsady. Edytowałem odpowiedź. – user9876

3

Można też owinąć bibliotekę libm który oferuje cbrt (pierwiastek) Funkcja:

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

daje oczekiwane

-2.0 
+6

Który poświęca funkcje między platformami dla czegoś, co można łatwo zaimplementować w czystym Pythonie. –

+3

Z drugiej strony ma zalety obliczania pierwiastka kostki (zamiast mocy 0.33333333333333331482961625624739099 ... rd, dlatego też OP napotkał problem na początek), a także jest bardziej dokładny i szybszy na niektórych platformach . Jeśli nie potrzebujesz przenośności, może to być bardzo praktyczne rozwiązanie. –

3

Korzeń sześcienny liczby ujemnej jest po prostu ujemnym względem sześciennego pierwiastka wartości bezwzględnej tej liczby.

czyli x^(1/3) dla x < 0 jest taka sama jak (-1) * (| x |)^(1/3)

Wystarczy dokonać liczbą dodatnią, a następnie wykonaj sześcienny korzeń.

18

Proste użycie De Moivre's formula, wystarcza, aby pokazać, że pierwiastek kostki wartości, niezależnie od znaku, jest funkcją wielowartościową. Oznacza to, że dla dowolnej wartości wejściowej będą trzy rozwiązania. Większość przedstawionych rozwiązań zwraca jedynie zasadę główną. Poniżej przedstawiono rozwiązanie, które zwraca wszystkie prawidłowe korzenie i jawne testy dla nieskomplikowanych przypadków specjalnych.

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: Zgodnie z wnioskiem, w przypadkach, gdy jest to nieodpowiednie mieć zależność numpy poniższy kod robi to samo.

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' nie należy dzielić przez' 3': 'numpy.exp (1j * (arg + 2 * n * math.pi/3))'. Możesz także użyć 'math.cos + 1j * math.sin', jeśli chcesz pozbyć się zależności od numpy. –

+0

Dobrze pamiętam z mojej klasy matematycznej. Tak więc obecnie zaakceptowana odpowiedź jest niekompletna. –

+0

@MizardX - wymagany jest podział na trzy, stanowi on mianownik argumentu. Zobacz http://pl.wikipedia.org/wiki/De_Moivre%27s_formula#Aplikacje –

9

można uzyskać kompletny (wszystkie n korzenie) i bardziej ogólnych (oznaczenia, każde zasilanie) roztwór z:

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

Objaśnienie: a oznacza się przy użyciu równania x U = exp (u * log (x)). To rozwiązanie będzie wówczas jednym z korzeni, a aby uzyskać pozostałe, obróć je w złożonej płaszczyźnie o (pełny obrót)/t.

0

Można użyć cbrt z scipy.special:

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

ta działa również na tablicach.

0

Po prostu miałem bardzo podobny problem i znalazłem rozwiązanie NumPy z this forum post.

W skrócie, możemy użyć metod NumPy sign i absolute, aby nam pomóc. Oto przykład, który pracował dla mnie:

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

Więc wracając do pierwotnego problemu pierwiastek:

import numpy as np 

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

Mam nadzieję, że to pomaga.

0

Dla arytmetycznych kalkulatora jak odpowiedź w Pythonie 3:

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

lub -3.0**(1./3) Pythona 2.

Dla algebraicznej roztworu x**3 + (0*x**2 + 0*x) + 3 = 0 stosowania numpy:

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

tę działa również z numpy array:

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

dlaczego nie '(abs (n) * n) * (abs (n) ** (1./3))'? Z powodów wydajności staram się unikać podziału. –

+1

@Salixalba: Poważnie? W Pythonie wątpię, by zauważyłeś znaczącą różnicę w wydajności między dzieleniem i mnożeniem pływaków. (Twoja sugestia wylicza 'n ** 2' razy w rdzeniu kostki, a nie w rdzeniu kostki). –

Powiązane problemy