What is the correct, generic way to figure out if values of a type `T`

can be converted into another type `S`

**without loss of precision**?

`Base.typejoin`

cannot be used for this (eg for `(Int8, Int16)`

, it returns `Signed`

). `promote_type`

would allow `Int64`

to `Float64`

, which is not always lossless.

I want something like

```
mypromote(Int8, Int64) == Int64
mypromote(Int32, Float64) == Float64
mypromote(Int64, Float64) == Real
```

but I wonder if I can implement it without a lot of special cases.

To me it seems you could write something that would cover all of the â€śmachine numbersâ€ť using `sizeof`

, testing whether a type is signed, and testing whether itâ€™s `AbstractFloat`

or `Integer`

. Youâ€™d also have to implement a lookup involving these three values to return an appropriate type, and hence may need to mark it as `Base.@pure`

. (Though with constant-propagation, who knows?)

Of course this wonâ€™t cover the whole zoo of number types that Julia now supports (complex numbers, dual numbers, physical units, intervals, etc.). Being generic on that scale is a much harder problem.

1 Like

What he said.

```
import Base: promote_rule
for I in (:Int8, :Int16, :Int32, :Int64, :Int128)
for F in (:Float16, :Float32, :Float64)
@eval begin
if sizeof($I) < sizeof($F)
promote_rule(::Type{$I}, ::Type{$F}) = $F
elseif sizeof($I) < sizeof(widen($F))
promote_rule(::Type{$I}, ::Type{$F}) = widen($F)
elseif sizeof($I) < sizeof(widen(widen($F)))
promote_rule(::Type{$I}, ::Type{$F}) = widen(widen($F))
else
promote_rule(::Type{$I}, ::Type{$F}) = BigFloat
end
end
end
end
```