Type of real part (of complex array element)

I’m wondering whether there is a nice way of knowing the concrete type of the real part of a complex number, particularly something like eltype() for array elements. Right now, for an abstract array x, I’m using typeof(real(x[1])) which doesn’t look very elegant to me.

doesn’t this error if the first element is a complex number?

julia> a = rand(ComplexF64, 2)
2-element Vector{ComplexF64}:
  0.5195502761029972 + 0.5859175609101466im
 0.14489461056434805 + 0.7517867801602849im

julia> Real(a[1])
ERROR: InexactError: Real(0.5195502761029972 + 0.5859175609101466im)
Stacktrace:

Sorry I meant real(a[1]). I changed it in the original question.

oh, do this:

real(eltype(ary))

julia> a = rand(ComplexF64, 2);

julia> g(ary) = real(eltype(ary))
g (generic function with 1 method)

julia> @code_llvm g(a)
;  @ REPL[12]:1 within `g`
define nonnull {}* @julia_g_1270({}* nonnull align 16 dereferenceable(40) %0) #0 {
top:
  ret {}* inttoptr (i64 140291981193776 to {}*)
}
3 Likes

typeof(real(x[1])) is about as neat as it gets for a 3-step process. The types of the real and imaginary parts of a Complex{T} number are the same, so typeof(imag(x[1])) works just as well.

If you’re looking to figure out the type of a field given only the parametric type, e.g. eltype(x) returned Complex{Int64}, you could do fieldtype(Complex{Int64}, :re) or fieldtype(Complex{Int64}, 1) to get Int64. If you want to get Int64 through the parameter, I don’t think there’s a public API way to do that, but this works (Complex{Int64}).parameters[1].

EDIT: wow I didn’t know real worked on types too, looks like it does fieldtype(C, 1).

In my own code I frequently need to know the precision of complex types too, and I detect these at the function boundary, e.g.:

function myfunc(a::Complex{T}, args...) where T
   # do something with T (which could be Float32, Float64, Int...)
end

Alternatively, if you want to write a cute function that returns the precision of the Complex type, this will do:

function precision(::Complex{T}) where T
    return T
end

Edit: And for an array, you could add a second definition:

function precision(::AbstractArray{Complex{T}}) where T
    return T
end
5 Likes

Thanks all for the speedy help. Yes real(eltype(ary)) and detecting at the function boundary are two very elegant solutions. Since the type may be Real or Complex, real(eltype(ary)) does the job for me.

The question has been answered (real(eltype(x))), but I would still like to warn against the following solution:

This solutions has some serious drawbacks. While real(eltype(x)) works entirely in the type domain, the above requires accessing the array at runtime, and will actually error if the array is empty or has non-standard indexing (say, a single-element OffsetArray).

Also, this:

reaches into the internal implementation of Complex, which is not recommended.

2 Likes

BTW, this difference is also perhaps notable:

julia> x = [Complex{Real}(1, 2.1)]
1-element Vector{Complex{Real}}:
 1 + 2.1im

julia> typeof(real(x[1]))
Int64

julia> real(eltype(x))
Real
2 Likes