Skip to content

Commit

Permalink
Add checked_* methods for FixedDecimals
Browse files Browse the repository at this point in the history
  • Loading branch information
NHDaly committed Dec 7, 2023
1 parent c81bb83 commit eda2525
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 2 deletions.
45 changes: 45 additions & 0 deletions src/FixedPointDecimals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,51 @@ if VERSION >= v"1.4.0-"
end
end

# --- Checked arithmetic ---

Base.checked_add(x::FD, y::FD) = Base.checked_add(promote(x, y)...)
Base.checked_sub(x::FD, y::FD) = Base.checked_sub(promote(x, y)...)
Base.checked_mul(x::FD, y::FD) = Base.checked_mul(promote(x, y)...)
Base.checked_div(x::FD, y::FD) = Base.checked_div(promote(x, y)...)

Base.checked_add(x, y::FD) = Base.checked_add(promote(x, y)...)
Base.checked_add(x::FD, y) = Base.checked_add(promote(x, y)...)
Base.checked_sub(x, y::FD) = Base.checked_sub(promote(x, y)...)
Base.checked_sub(x::FD, y) = Base.checked_sub(promote(x, y)...)
Base.checked_mul(x, y::FD) = Base.checked_mul(promote(x, y)...)
Base.checked_mul(x::FD, y) = Base.checked_mul(promote(x, y)...)
Base.checked_div(x, y::FD) = Base.checked_div(promote(x, y)...)
Base.checked_div(x::FD, y) = Base.checked_div(promote(x, y)...)

function Base.checked_add(x::T, y::T) where {T<:FD}
z, b = Base.add_with_overflow(x.i, y.i)
b && Base.Checked.throw_overflowerr_binaryop(:+, x, y)
return reinterpret(T, z)
end
function Base.checked_sub(x::T, y::T) where {T<:FD}
z, b = Base.sub_with_overflow(x.i, y.i)
b && Base.Checked.throw_overflowerr_binaryop(:-, x, y)
return reinterpret(T, z)
end
function Base.checked_mul(x::D, y::D) where {T, f, D<:FD{T,f}}
powt = coefficient(FD{T, f})
quotient, remainder = fldmodinline(widemul(x.i, y.i), powt)
v = _round_to_nearest(quotient, remainder, powt)
typemin(T) <= v <= typemax(T) || Base.Checked.throw_overflowerr_binaryop(:*, x, y)
return reinterpret(FD{T, f}, T(v))
end
#function Base.checked_div(x::FD{T,f}, y::FD{T,f}) where {T,f}
function Base.checked_div(x::D, y::D) where {T, f, D<:FD{T,f}}
C = coefficient(FD{T, f})
v1 = div(promote(x.i, y.i)...)
v2, b = Base.Checked.mul_with_overflow(C, v1)
b && Base.Checked.throw_overflowerr_binaryop(:÷, x, y)
typemin(T) <= v2 <= typemax(T) || Base.Checked.throw_overflowerr_binaryop(:÷, x, y)
return reinterpret(FD{T, f}, T(v2))
end

# --------------------------

Base.convert(::Type{AbstractFloat}, x::FD) = convert(floattype(typeof(x)), x)
function Base.convert(::Type{TF}, x::FD{T, f}) where {TF <: AbstractFloat, T, f}
convert(TF, x.i / coefficient(FD{T, f}))::TF
Expand Down
7 changes: 5 additions & 2 deletions test/FixedDecimal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -625,8 +625,11 @@ end
end

@testset "limits" begin
@test_throws InexactError Int8(1) / FD{Int8,2}(0.4)
@test_throws InexactError FD{Int8,2}(1) / FD{Int8,2}(0.4)
@test_throws OverflowError Base.checked_add(FD{Int8,2}(1), FD{Int8,2}(1))
@test_throws OverflowError Base.checked_add(FD{Int8,2}(1), FD{Int8,2}(0.4))

@test_throws OverflowError Base.checked_div(Int8(1), FD{Int8,2}(0.4))
@test_throws OverflowError Base.checked_div(FD{Int8,2}(1), FD{Int8,2}(0.4))
end

@testset "limits of $T" for T in CONTAINER_TYPES
Expand Down

0 comments on commit eda2525

Please sign in to comment.