Skip to content

Commit

Permalink
Fix methods ambiguities
Browse files Browse the repository at this point in the history
  • Loading branch information
pabloferz committed Sep 19, 2022
1 parent 93cec87 commit 2f062ac
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 4 deletions.
32 changes: 28 additions & 4 deletions src/FixedPointDecimals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ function Base.widemul(x::FD{T, f}, y::Integer) where {T, f}
reinterpret(FD{typeof(i), f}, i)
end
Base.widemul(x::Integer, y::FD) = widemul(y, x)
# needed to avoid ambiguities
function Base.widemul(x::FD{T, f}, y::Bool) where {T, f}
i = widemul(x.i, y)
reinterpret(FD{typeof(i), f}, i)
end
Base.widemul(x::Bool, y::FD) = widemul(y, x)

"""
_round_to_even(quotient, remainder, divisor)
Expand Down Expand Up @@ -239,13 +245,20 @@ for fn in [:trunc, :floor, :ceil]
@eval (Base.$fn(::Type{TI}, x::FD)::TI) where {TI <: Integer} = $fn(x)

# round/trunc/ceil/flooring to FD; generic
@eval function Base.$fn(::Type{FD{T, f}}, x::Real) where {T, f}
@eval function $(Symbol(:_, fn))(::Type{FD{T, f}}, x::Real) where {T, f}
powt = coefficient(FD{T, f})
# Use machine Float64 if possible, but fall back to BigFloat if we need
# more precision. 4f bits suffices.
val = _apply_exact_float($(Symbol(fn, "mul")), T, x, powt)
reinterpret(FD{T, f}, val)
end
@eval function Base.$fn(::Type{FD{T, f}}, x::Real) where {T, f}
$(Symbol(:_, fn))(FD{T, f}, x)
end
# needed to avoid ambiguities
@eval function Base.$fn(::Type{FD{T, f}}, x::Rational) where {T, f}
$(Symbol(:_, fn))(FD{T, f}, x)
end
end
function Base.round(::Type{TI}, x::FD, ::RoundingMode{:Nearest}=RoundNearest) where {TI <: Integer}
convert(TI, round(x))::TI
Expand All @@ -254,9 +267,18 @@ function Base.round(::Type{FD{T, f}}, x::Real, ::RoundingMode{:Nearest}=RoundNea
reinterpret(FD{T, f}, round(T, x * coefficient(FD{T, f})))
end

# needed to avoid ambiguity
function Base.round(::Type{FD{T, f}}, x::Rational, ::RoundingMode{:Nearest}=RoundNearest) where {T, f}
reinterpret(FD{T, f}, round(T, x * coefficient(FD{T, f})))
# needed to avoid ambiguities
@static if Base.VERSION >= v"1.6"
function Base.round(::Type{FD{T, f}}, x::Rational{Tr}, ::RoundingMode{:Nearest}=RoundNearest) where {T, Tr, f}
reinterpret(FD{T, f}, round(T, x * coefficient(FD{T, f})))
end
function Base.round(::Type{FD{T, f}}, x::Rational{Bool}, ::RoundingMode{:Nearest}=RoundNearest) where {T, f}
reinterpret(FD{T, f}, round(T, x * coefficient(FD{T, f})))
end
else
function Base.round(::Type{FD{T, f}}, x::Rational, ::RoundingMode{:Nearest}=RoundNearest) where {T, f}
reinterpret(FD{T, f}, round(T, x * coefficient(FD{T, f})))
end
end

# conversions and promotions
Expand Down Expand Up @@ -325,6 +347,8 @@ function Base.convert(::Type{TR}, x::FD{T, f}) where {TR <: Rational, T, f}
end

(::Type{T})(x::FD) where {T<:Union{AbstractFloat,Integer,Rational}} = convert(T, x)
# needed to avoid ambiguities
Bool(x::FD) = x == 0 ? false : (x == 1 ? true : throw(InexactError(:Bool, Bool, x)))

Base.promote_rule(::Type{FD{T, f}}, ::Type{<:Integer}) where {T, f} = FD{T, f}
Base.promote_rule(::Type{<:FD}, ::Type{TF}) where {TF <: AbstractFloat} = TF
Expand Down
13 changes: 13 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1045,4 +1045,17 @@ end
end
end

@testset "method ambiguities" begin
fd1 = FD{Int8, 1}(0.1)
fd2 = FD{Int, 1}(1.0)

@test widemul(fd1, false) == widemul(false, fd1) == FD{Int8, 1}(0.0)
@test ceil(FD{Int, 1}, 99 // 100) == fd2
@test round(FD{Int, 1}, true // true) == fd2
@test invoke(round, Tuple{Type{FD{Int, 1}}, Rational}, FD{Int, 1}, 99 // 100) == fd2

@test Bool(fd2)
@test_throws InexactError Bool(fd1)
end

end # global testset

0 comments on commit 2f062ac

Please sign in to comment.