Skip to content

Commit 9c52516

Browse files
committed
Commonize promotion rules
This makes the promotion rules for `Fixed` consistent with the rules used within `Normed`: - `Fixed` and `Integer` are promoted to `floattype` - `Fixed` and `AbstractFloat` are promoted to `floattype` with sufficient precision This adds the rule: - `Fixed` and `Normed` are promoted to `floattype` This also stops using `@generated` function.
1 parent 40c9117 commit 9c52516

File tree

6 files changed

+68
-56
lines changed

6 files changed

+68
-56
lines changed

src/FixedPointNumbers.jl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,35 @@ include("normed.jl")
311311
include("deprecations.jl")
312312
const UF = (N0f8, N6f10, N4f12, N2f14, N0f16)
313313

314+
# Promotions
315+
promote_rule(::Type{X}, ::Type{Tf}) where {X <: FixedPoint, Tf <: AbstractFloat} =
316+
promote_type(floattype(X), Tf)
317+
318+
# Note that `Tr` does not always have enough domains.
319+
promote_rule(::Type{X}, ::Type{Tr}) where {X <: FixedPoint, Tr <: Rational} = Tr
320+
321+
promote_rule(::Type{X}, ::Type{Ti}) where {X <: FixedPoint, Ti <: Integer} = floattype(X)
322+
323+
function promote_rule(::Type{X1}, ::Type{X2}) where {T1, f1, X1 <: FixedPoint{T1,f1},
324+
T2, f2, X2 <: FixedPoint{T2,f2}}
325+
X = wrapper(X1)
326+
X !== wrapper(X2) && return promote_type(floattype(X1), floattype(X2))
327+
328+
f = max(f1, f2) # ensure we have enough precision
329+
Tp = promote_type(T1, T2)
330+
T = (T1 <: Signed || T2 <: Signed) ? signedtype(Tp) : Tp
331+
# make sure we have enough integer bits
332+
m = max(nbitsint(X1), nbitsint(X2))
333+
_widen_rawtype(X{T,f}, m)
334+
end
335+
336+
function _widen_rawtype(::Type{X}, m) where {T, f, X<:FixedPoint{T,f}}
337+
nbitsint(X) >= m && return X
338+
Tw = widen1(T)
339+
T === Tw && return X
340+
_widen_rawtype(wrapper(X){Tw,f}, m)
341+
end
342+
314343
# Promotions for reductions
315344
const Treduce = Float64
316345
Base.add_sum(x::FixedPoint, y::FixedPoint) = Treduce(x) + Treduce(y)

src/fixed.jl

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -195,24 +195,5 @@ length(r::AbstractUnitRange{F}) where {F <: Fixed{<:SShorterThanInt,f}} where {f
195195
length(r::AbstractUnitRange{F}) where {F <: Fixed{T}} where {T <: Signed} =
196196
checked_add(checked_sub(floor(T, last(r)), floor(T, first(r))), oneunit(T))
197197

198-
promote_rule(ft::Type{Fixed{T,f}}, ::Type{TI}) where {T,f,TI <: Integer} = Fixed{T,f}
199-
promote_rule(::Type{Fixed{T,f}}, ::Type{TF}) where {T,f,TF <: AbstractFloat} = TF
200-
promote_rule(::Type{Fixed{T,f}}, ::Type{Rational{TR}}) where {T,f,TR} = Rational{TR}
201-
202-
@generated function promote_rule(::Type{Fixed{T1,f1}}, ::Type{Fixed{T2,f2}}) where {T1,T2,f1,f2}
203-
f = max(f1, f2) # ensure we have enough precision
204-
T = promote_type(T1, T2)
205-
# make sure we have enough integer bits
206-
i1, i2 = bitwidth(T1)-f1, bitwidth(T2)-f2 # number of integer bits for each
207-
i = bitwidth(T)-f
208-
while i < max(i1, i2)
209-
Tw = widen1(T)
210-
T == Tw && break
211-
T = Tw
212-
i = bitwidth(T)-f
213-
end
214-
:(Fixed{$T,$f})
215-
end
216-
217198
# TODO: Document and check that it still does the right thing.
218199
decompose(x::Fixed{T,f}) where {T,f} = x.i, -f, 1

src/normed.jl

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -303,24 +303,3 @@ length(r::AbstractUnitRange{N}) where {N <: Normed{<:UShorterThanInt}} =
303303
floor(Int, last(r)) - floor(Int, first(r)) + 1
304304
length(r::AbstractUnitRange{N}) where {N <: Normed{T}} where {T<:Unsigned} =
305305
r.start > r.stop ? T(0) : checked_add(floor(T, last(r)) - floor(T, first(r)), oneunit(T))
306-
307-
# Promotions
308-
promote_rule(::Type{T}, ::Type{Tf}) where {T <: Normed,Tf <: AbstractFloat} = promote_type(floattype(T), Tf)
309-
promote_rule(::Type{T}, ::Type{R}) where {T <: Normed,R <: Rational} = R
310-
function promote_rule(::Type{T}, ::Type{Ti}) where {T <: Normed,Ti <: Union{Signed, Unsigned}}
311-
floattype(T)
312-
end
313-
@generated function promote_rule(::Type{Normed{T1,f1}}, ::Type{Normed{T2,f2}}) where {T1,T2,f1,f2}
314-
f = max(f1, f2) # ensure we have enough precision
315-
T = promote_type(T1, T2)
316-
# make sure we have enough integer bits
317-
i1, i2 = bitwidth(T1)-f1, bitwidth(T2)-f2 # number of integer bits for each
318-
i = bitwidth(T)-f
319-
while i < max(i1, i2)
320-
Tw = widen1(T)
321-
T == Tw && break
322-
T = Tw
323-
i = bitwidth(T)-f
324-
end
325-
:(Normed{$T,$f})
326-
end

src/utilities.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# utility functions and macros, which are independent of `FixedPoint`
22
bitwidth(T::Type) = 8sizeof(T)
33

4+
widen1(T::Type) = T # fallback
45
widen1(::Type{Int8}) = Int16
56
widen1(::Type{UInt8}) = UInt16
67
widen1(::Type{Int16}) = Int32
@@ -9,8 +10,6 @@ widen1(::Type{Int32}) = Int64
910
widen1(::Type{UInt32}) = UInt64
1011
widen1(::Type{Int64}) = Int128
1112
widen1(::Type{UInt64}) = UInt128
12-
widen1(::Type{Int128}) = Int128
13-
widen1(::Type{UInt128}) = UInt128
1413
widen1(x::Integer) = x % widen1(typeof(x))
1514

1615
signedtype(::Type{T}) where {T <: Integer} = typeof(signed(zero(T)))
@@ -48,3 +47,5 @@ if !signbit(signed(unsafe_trunc(UInt, -12.345)))
4847
# exclude BigFloat (issue #202)
4948
_unsafe_trunc(::Type{T}, x::BigFloat) where {T <: Integer} = unsafe_trunc(T, x)
5049
end
50+
51+
wrapper(@nospecialize(T)) = Base.typename(T).wrapper

test/fixed.jl

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -455,13 +455,24 @@ end
455455
@test Fixed{Int16,3}(-1) == Fixed{Int8,5}(-1)
456456
@test Fixed{Int16,3}(0.25) == Fixed{Int8,5}(0.25)
457457

458-
@test promote_type(Q0f7,Float32,Int) == Float32
459-
@test promote_type(Q0f7,Int,Float32) == Float32
460-
@test promote_type(Int,Q0f7,Float32) == Float32
461-
@test promote_type(Int,Float32,Q0f7) == Float32
462-
@test promote_type(Float32,Int,Q0f7) == Float32
463-
@test promote_type(Float32,Q0f7,Int) == Float32
464-
@test promote_type(Q0f7,Q1f6,Q2f5,Q3f4,Q4f3,Q5f2) == Fixed{Int128,7}
458+
@test @inferred(promote_type(Q0f7, Float64)) === Float64
459+
@test @inferred(promote_type(Float32, Q7f24)) === Float64
460+
461+
@test @inferred(promote_type(Q0f7, Int8)) === Float32
462+
@test @inferred(promote_type(Int128, Q7f24)) === Float64
463+
464+
@test @inferred(promote_type(Q0f15, Rational{UInt8})) === Rational{UInt8}
465+
466+
@test @inferred(promote_type(Q0f7, Float32, Int)) === Float32
467+
@test @inferred(promote_type(Q0f7, Int, Float32)) === Float32
468+
@test @inferred(promote_type(Int, Q0f7, Float32)) === Float32
469+
@test @inferred(promote_type(Int, Float32, Q0f7)) === Float32
470+
@test @inferred(promote_type(Float32, Int, Q0f7)) === Float32
471+
@test @inferred(promote_type(Float32, Q0f7, Int)) === Float32
472+
473+
@test @inferred(promote_type(Q0f7,Q1f6,Q2f5,Q3f4,Q4f3,Q5f2)) == Fixed{Int128,7}
474+
475+
@test @inferred(promote_type(Q0f7, N0f32)) === Float64
465476
end
466477

467478
@testset "show" begin

test/normed.jl

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -485,13 +485,24 @@ end
485485
@test Normed{UInt16,4}(1) == Normed{UInt8,6}(1)
486486
@test Normed{UInt16,4}(0.2) == Normed{UInt8,6}(0.2)
487487

488-
@test promote_type(N0f8,Float32,Int) == Float32
489-
@test promote_type(N0f8,Int,Float32) == Float32
490-
@test promote_type(Int,N0f8,Float32) == Float32
491-
@test promote_type(Int,Float32,N0f8) == Float32
492-
@test promote_type(Float32,Int,N0f8) == Float32
493-
@test promote_type(Float32,N0f8,Int) == Float32
494-
@test promote_type(N0f8,N1f7,N2f6,N3f5,N4f4,N5f3) == Normed{UInt128,8}
488+
@test @inferred(promote_type(N0f8, Float64)) === Float64
489+
@test @inferred(promote_type(Float32, N8f24)) === Float64
490+
491+
@test @inferred(promote_type(N0f8, Int8)) === Float32
492+
@test @inferred(promote_type(Int128, N8f24)) === Float64
493+
494+
@test @inferred(promote_type(N0f16, Rational{Int8})) === Rational{Int8}
495+
496+
@test @inferred(promote_type(N0f8, Float32, Int)) === Float32
497+
@test @inferred(promote_type(N0f8, Int, Float32)) === Float32
498+
@test @inferred(promote_type(Int, N0f8, Float32)) === Float32
499+
@test @inferred(promote_type(Int, Float32, N0f8)) === Float32
500+
@test @inferred(promote_type(Float32, Int, N0f8)) === Float32
501+
@test @inferred(promote_type(Float32, N0f8, Int)) === Float32
502+
503+
@test @inferred(promote_type(N0f8,N1f7,N2f6,N3f5,N4f4,N5f3)) === Normed{UInt128,8}
504+
505+
@test @inferred(promote_type(N0f8, Q0f31)) === Float64
495506
end
496507

497508
@testset "show" begin

0 commit comments

Comments
 (0)