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.

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
│ %6 = (Base.add_float)(%4, %5)::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`

.