From 2f062acc74e8acefee8a9771154c60109375a3da Mon Sep 17 00:00:00 2001 From: Pablo Zubieta <8410335+pabloferz@users.noreply.github.com> Date: Sat, 10 Sep 2022 22:44:45 -0500 Subject: [PATCH] Fix methods ambiguities --- src/FixedPointDecimals.jl | 32 ++++++++++++++++++++++++++++---- test/runtests.jl | 13 +++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/src/FixedPointDecimals.jl b/src/FixedPointDecimals.jl index b7f5dc8..2ed7159 100644 --- a/src/FixedPointDecimals.jl +++ b/src/FixedPointDecimals.jl @@ -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) @@ -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 @@ -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 @@ -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 diff --git a/test/runtests.jl b/test/runtests.jl index 230a021..493268a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -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