In order to improve np.roots performance on cubic equation, I try to implement Cardan(o) Method :
def cardan(a,b,c,d):
    #"resolve P=ax^3+bx^2+cx+d=0" 
    #"x=z-b/a/3=z-z0 => P=z^3+pz+q"
    z0=b/3/a
    a2,b2 = a*a,b*b    
    p=-b2/3/a2 +c/a
    q=(b/27*(2*b2/a2-9*c/a)+d)/a
    D=-4*p*p*p-27*q*q+0j
    r=sqrt(-D/27)
    J=-0.5+0.86602540378443871j # exp(2i*pi/3)
    u=((-q+r)/2)**(1/3)
    v=((-q-r)/2)**(1/3)
    return u+v-z0,u*J+v/J-z0,u/J+v*J-z0
It works well when roots are real:
In [2]: P=poly1d([1,2,3],True)
In [3]: roots(P)
Out[3]: array([ 3.,  2.,  1.])
In [4]: cardan(*P)
Out[4]: ((3+0j), (1+0j), (2+1.110e-16j))
But fails in the complex case :
In [8]: P=poly1d([1,-1j,1j],True)
In [9]: P
Out[9]: poly1d([ 1., -1.,  1., -1.])
In [10]: roots(P)
Out[10]: array([  1.0000e+00+0.j,   7.771e-16+1.j,   7.771e-16-1.j])
In [11]: cardan(*P)
Out[11]: ((1.366+0.211j),(5.551e-17+0.577j),(-0.366-0.788j))
I guess that the problem is the evaluation of u and v by cube roots .
Theory say uv=-p/3, but here uv=pJ/3: (u,v) is not a good pair of roots.
What is the best way to obtain a correct pair in all cases ?
EDIT
After @Sally post, I can precise the problem. The good pair is not  always (u,v), it can be  (u,vJ) or (uJ,v). So the question could be :
- is there a straightforward method to catch the good pair ?
And ultimate : for the moment, by compiling this code with Numba, it's 20x faster than np.roots .
- is there a better algorithm to compute the three roots of a cubic equation ?
 
    