Promote/widen numerical types under +, *, sqrt, log

I have a tuple of numerical types. I am looking for the type that would result after combining these types with +, *, sqrt, log. Is there a function to do this?

Context: I am writing a function (too complex for an MWE here, generated code) that uses these operations, and I want type stability. Primarily it would be called with Float64, but other float types and the occasional Integer should work, too.

I could use promote_type, except that log(::Int) isa Float64. I can work around this with something like

julia> function promote_alg(Ts...)
           S = promote_type(Ts...)
           S <: Integer ? promote_type(S, Float64) : S
       end
promote_alg (generic function with 2 methods)

julia> promote_alg(Int, Float64, Float32)
Float64

julia> promote_alg(Float16, Float32, Float32)
Float32

julia> promote_alg(Int, Int, Int8)
Float64

but I wonder if this has a name in Base.

There are no hard-coded promotion-like methods for this. This works most of the time:

julia> Base.return_types((x,y)->log(x)*y, (Int,Int))
1-element Array{Any,1}:
 Float64
1 Like

In LinAlg, it is typically done something like:

typeof(sqrt(one(T) * one(T)))

This tends to be computed at compile time.

See https://github.com/JuliaLang/julia/blob/15c467354e46821959dd0336bba5c569448b085f/base/linalg/qr.jl#L238 for an example.

2 Likes

There’s also promote_op:

julia> Base.promote_op(log, Int)
Float64

julia> Base.promote_op(+, Int, Float64)
Float64

That should require knowing the result type.

Precisely. I am accumulating various results, initialized with a zero(T) and a one(T). I want to calculate T to not have variables change type during the calculation.

Potentially relevant: Ridiculous idea: types from the future (in which the easiest suggestion turned out be letting map do all the hard work of figuring out a nice stable return type).