How to extend cube root to complex numbers?

I can find square root of complex numbers but not cube root

julia> sqrt(1 + 2im)
1.272019649514069 + 0.7861513777574233im

julia> cbrt(1 + 2im)
ERROR: MethodError: no method matching cbrt(::Complex{Int64})
Closest candidates are:
  cbrt(::BigFloat) at mpfr.jl:619
  cbrt(::Float16) at math.jl:1125
  cbrt(::Union{Float32, Float64}) at special/cbrt.jl:144
  ...
Stacktrace:
 [1] top-level scope at REPL[2]:1

So this is my attempt to extend cube root of complex numbers. Am I doing this right?

julia> import Base: cbrt

julia> cbrt(x::Complex{T}) where T = x^(one(T)/(one(T)+one(T)+one(T)))
cbrt (generic function with 6 methods)

julia> cbrt(1 + 2im)
1.2196165079717578 + 0.47171126778938893im
1 Like

What about the two other complex roots?

1 Like

I guess cbrt could be extended to complex numbers. Maybe open an issue? In the meantime,

julia> (1+2im)^(1/3)
1.2196165079717578 + 0.47171126778938893im

Like sqrt, it would have to pick one. AFAIK it is commonly called the principal root.

1 Like

Things can get weird here. If you use the principal root, then it is not always true that

(ab)^(1/3) = a^(1/3) b^(1/3)

It’s exactly the same situation as with sqrt:

a = complex(-1)
sqrt(a*a) == 1
sqrt(a)*sqrt(a) == -1
2 Likes

I opened an issue: https://github.com/JuliaLang/julia/issues/36534

However, the choice of branch cut isn’t immediately clear to me, since the obvious choice is inconsistent with how cbrt is defined for real values:

# naive definition:
julia> Base.cbrt(z::Complex) = cbrt(abs(z)) * cis(angle(z)/3)

julia> cbrt(-3)
-1.4422495703074083

julia> cbrt(-3+0im)
0.7211247851537043 + 1.2490247664834064im

julia> (-3+0im)^(1//3)
0.7211247851537042 + 1.2490247664834064im
2 Likes

I don’t think there is an obvious choice. If you want a positive real root for a positive real input, you are still in a hole. If you integrate around a contour about the origin, you’ll cross a branch cut and get different values as the argument increases. So if z=r exp(im*theta) and cbrt(z) = r exp(im *theta/3), one pass around the contour does not take you back to where you started. All you can do is keep the books correctly as you traverse a contour.

Same story z^(1/n) for n =2, 3, …

2 Likes

In Mathematica, cbrt is only defined to return the real value of cuberoot.

I don’t think it is a good idea to define cbrt for complex value because it would cause discontinuity (depending on whether the arguement is Real or Complex). But certainly the documentation for crbt should be updated to mention that

cbrt(-27) == -3 while (-27+0im)^(1/3) == 1.5 + 2.598076211353316im

so cbrt will only return a real result (and never a complex result)

1 Like