# Lossless type promotion

**URL:** <https://discourse.julialang.org/t/lossless-type-promotion/17465>\
**Category:** General Usage\
**Tags:** question\
**Created:** [November 13, 2018, 9:08am UTC](https://discourse.julialang.org/t/lossless-type-promotion/17465 "2018-11-13T09:08:33Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [November 13, 2018, 9:08am UTC](https://discourse.julialang.org/t/lossless-type-promotion/17465/1 "2018-11-13T09:08:33Z")

</div>

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

```julia
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.

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [November 13, 2018, 10:51am UTC](https://discourse.julialang.org/t/lossless-type-promotion/17465/2 "2018-11-13T10:51:43Z")

</div>

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.

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [November 13, 2018, 11:53am UTC](https://discourse.julialang.org/t/lossless-type-promotion/17465/3 "2018-11-13T11:53:01Z")

</div>

What he said.

```julia
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

```
