Help with promote on FixedPointNumbers

question

#1

Hello,
what is the right way in using FixedPointNumbers.jl to achieve custom math operation:

using FixedPointNumbers
a = convert(Fixed{Int8, 6}, 1.0)
b = convert(Fixed{Int8, 6}, 0.5)
c = convert(Fixed{Int16, 6}, 0.25)

#working
julia> a*b
0.5Q1f6
julia> a*c
ERROR: no promotion exists for FixedPointNumbers.Fixed{Int8,6} and FixedPointNum
bers.Fixed{Int16,6}
Stacktrace:
 [1] promote_type(::Type{FixedPointNumbers.Fixed{Int8,6}}, ::Type{FixedPointNumb
ers.Fixed{Int16,6}}) at .\promotion.jl:161
 [2] promote at .\promotion.jl:175 [inlined]
 [3] *(::FixedPointNumbers.Fixed{Int8,6}, ::FixedPointNumbers.Fixed{Int16,6}) at
 .\promotion.jl:250

I tried

import Base.promote_rule
promote_rule(::Type{Fixed{T1,f}}, ::Type{Fixed{T2,f}}) where {T1<:Signed,
 T2<:Signed,f} = sizeof(T1)> sizeof(T2) ? Fixed{T1,f} : Fixed{T2,f}

in order to widen the result (just example, I’d be more careful with widening for different operations). But still the promote machinery doesn’t work.

promote(a,c)
ERROR: no promotion exists for FixedPointNumbers.Fixed{Int8,6} and FixedPointNum
bers.Fixed{Int16,6}
Stacktrace:
 [1] promote_type(::Type{FixedPointNumbers.Fixed{Int8,6}}, ::Type{FixedPointNumb
ers.Fixed{Int16,6}}) at .\promotion.jl:161
 [2] promote(::FixedPointNumbers.Fixed{Int8,6}, ::FixedPointNumbers.Fixed{Int16,
6}) at .\promotion.jl:175

What is the right way to define the promotion rules?
Thanks,
Petr


#2

You could define

Base.promote_type(::Type{Fixed{S, f}}, ::Type{Fixed{T, f}}) where {f, S, T} =
    Fixed{promote_type(S, T), f}

as the error message suggests, but then there appears to be no convert method, so it does not help you much (unless, of course, you are willing to define one too).

I would recommend that you open an issue for the package.


#3

After some further investigation, these are my findings:

  • Beware worl-age problem!
  • Base.promote_rule definition is the first thing to try (and what the manual suggests).
  • Nonexisting promote_type error is just a fallback if promote_rule is not defined
    and my first code would do the right thing if I wasn’t bitten by world age problem. Before the method definition I already executed a*c, thus forced Julia to compile the function without the promote_rule. And then the old one was used.

One has to be careful whenever import Base.any_function appears in his code and the function is not top level but used internally by any other function. I might make a PR to mention this in the relevant places of the manual.