Skip to content

Commit

Permalink
Add checked / operation for FDs: checked_decimal_division
Browse files Browse the repository at this point in the history
  • Loading branch information
NHDaly committed Dec 7, 2023
1 parent d3a3b4c commit 831b4ff
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 0 deletions.
24 changes: 24 additions & 0 deletions src/FixedPointDecimals.jl
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,30 @@ function Base.checked_div(x::FD{T,f}, y::FD{T,f}) where {T<:Integer,f}
return reinterpret(FD{T, f}, v)
end

# We introduce a new function for this since Base.Checked only supports integers, and ints
# don't have a decimal division operation.
"""
FixedPointDecimals.checked_decimal_division(x::FD, y::FD) -> FD
Calculates `x / y`, checking for overflow errors where applicable.
The overflow protection may impose a perceptible performance penalty.
See also:
- `Base.checked_div` for truncating division.
"""
checked_decimal_division(x::FD, y::FD) = checked_decimal_division(promote(x, y)...)
checked_decimal_division(x, y::FD) = checked_decimal_division(promote(x, y)...)
checked_decimal_division(x::FD, y) = checked_decimal_division(promote(x, y)...)

function checked_decimal_division(x::FD{T,f}, y::FD{T,f}) where {T<:Integer,f}
powt = coefficient(FD{T, f})
quotient, remainder = fldmod(widemul(x.i, powt), y.i)
v = _round_to_nearest(quotient, remainder, y.i)
typemin(T) <= v <= typemax(T) || Base.Checked.throw_overflowerr_binaryop(:/, x, y)
return reinterpret(FD{T, f}, v)
end

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

Base.convert(::Type{AbstractFloat}, x::FD) = convert(floattype(typeof(x)), x)
Expand Down
7 changes: 7 additions & 0 deletions test/FixedDecimal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,13 @@ end

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

@testset "checked_decimal_division" begin
using FixedPointDecimals: checked_decimal_division

@test checked_decimal_division(Int8(1), FD{Int8,2}(0.8)) == FD{Int8,2}(1.25)
@test_throws OverflowError checked_decimal_division(Int8(1), FD{Int8,2}(0.7))
end
end

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

0 comments on commit 831b4ff

Please sign in to comment.