# Alternative Complex type

Is there a complex type saving the angle and the radius instead of the imaginary and the real part?

I think if there are a lot of multiplications this would be faster.

I don’t think there is but it would be relatively easy to implement, e.g.

``````struct PolarComplex{T<:Real} <: Number
R::T
θ::T
PolarComplex(R::T, θ::T) where T <: Real =
new{T}(R, mod(θ,2π))
end

PolarComplex(x::Real, y::Real) = PolarComplex(promote(x,y)...)

Base.angle(x::PolarComplex) = x.θ
Base.abs(x::PolarComplex) = x.R

Base.:*(x::PolarComplex, y::PolarComplex) =
PolarComplex( abs(x)*abs(y), angle(x)+angle(y) )

z1  = (exp(2im)) * (3*exp(4im))
z1 = PolarComplex(abs(z1), angle(z1))

z2 = PolarComplex(1.0,2.0) * PolarComplex(3.0,4.0)

@assert z1 == z2
``````

The promotion, conversion and constructor part is a bit more complicated but you could pretty much copy the Complex implementation in Base.

I don’t know if it’s any faster though (I shouldn’t do the mod probably).

5 Likes

I think there are still some safety checks going on, but I have no idea how to remove those.

``````> z1p = PolarComplex(abs(z1), angle(z1))
> @code_typed z1p*z1p
CodeInfo(
1 ─ %1  = (Base.getfield)(x, :R)::Float64
│   %2  = (Base.getfield)(y, :R)::Float64
│   %3  = (Base.mul_float)(%1, %2)::Float64
│   %4  = (Base.getfield)(x, :θ)::Float64
│   %5  = (Base.getfield)(y, :θ)::Float64
│   %7  = (Base.rem_float)(%6, 6.28319)::Float64
│   %8  = (Base.eq_float)(%7, 0.0)::Bool
│   %9  = (Base.and_int)(%8, true)::Bool
│   %10 = (Base.and_int)(%9, true)::Bool
└──       goto #3 if not %10
2 ─ %12 = (Base.copysign_float)(%7, 6.28319)::Float64
└──       goto #6
3 ─ %14 = (Base.lt_float)(0.0, %7)::Bool
│   %15 = (Base.eq_float)(0.0, %7)::Bool
│   %16 = (Base.and_int)(%15, false)::Bool
│   %17 = (Base.or_int)(%14, %16)::Bool
│   %18 = (%17 === true)::Bool
│   %19 = (Base.not_int)(%18)::Bool
└──       goto #5 if not %19
4 ─ %21 = (Base.add_float)(%7, 6.28319)::Float64
└──       goto #6
5 ─       goto #6
6 ┄ %24 = φ (#2 => %12, #4 => %21, #5 => %7)::Float64
│   %25 = %new(PolarComplex{Float64}, %3, %24)::PolarComplex{Float64}
└──       goto #7
7 ─       return %25
) => PolarComplex{Float64}
``````

This is only because of the `mod(θ,2π)` call (it would probably be more exact to use `mod2pi(θ)` here instead). You could leave this out instead, but if you’re doing a lot of operations, it could accumulate quite quickly and result in a loss of precision.

3 Likes

You could remove it yes, I mainly put it there because otherwise my assertion at the end was failing.

You can always overload the `==` operator to do that, but if you’re calling this method quite often, it’s probably better to use `mod2pi` in the constructor.

Something that might make this implementation better is to make the `Pi` part of the radius implicit. This would make it better able to represent angles that are multiples of `Pi`.