Skip to content

Commit 9da03cd

Browse files
committed
Add checked_* methods for FixedDecimals
1 parent c81bb83 commit 9da03cd

File tree

2 files changed

+49
-2
lines changed

2 files changed

+49
-2
lines changed

src/FixedPointDecimals.jl

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,50 @@ if VERSION >= v"1.4.0-"
380380
end
381381
end
382382

383+
# --- Checked arithmetic ---
384+
385+
Base.checked_add(x::FD, y::FD) = Base.checked_add(promote(x, y)...)
386+
Base.checked_sub(x::FD, y::FD) = Base.checked_sub(promote(x, y)...)
387+
Base.checked_mul(x::FD, y::FD) = Base.checked_mul(promote(x, y)...)
388+
Base.checked_div(x::FD, y::FD) = Base.checked_div(promote(x, y)...)
389+
390+
Base.checked_add(x, y::FD) = Base.checked_add(promote(x, y)...)
391+
Base.checked_add(x::FD, y) = Base.checked_add(promote(x, y)...)
392+
Base.checked_sub(x, y::FD) = Base.checked_sub(promote(x, y)...)
393+
Base.checked_sub(x::FD, y) = Base.checked_sub(promote(x, y)...)
394+
Base.checked_mul(x, y::FD) = Base.checked_mul(promote(x, y)...)
395+
Base.checked_mul(x::FD, y) = Base.checked_mul(promote(x, y)...)
396+
Base.checked_div(x, y::FD) = Base.checked_div(promote(x, y)...)
397+
Base.checked_div(x::FD, y) = Base.checked_div(promote(x, y)...)
398+
399+
function Base.checked_add(x::T, y::T) where {T<:FD}
400+
z, b = Base.add_with_overflow(x.i, y.i)
401+
b && Base.Checked.throw_overflowerr_binaryop(:+, x, y)
402+
return reinterpret(T, z)
403+
end
404+
function Base.checked_sub(x::T, y::T) where {T<:FD}
405+
z, b = Base.sub_with_overflow(x.i, y.i)
406+
b && Base.Checked.throw_overflowerr_binaryop(:-, x, y)
407+
return reinterpret(T, z)
408+
end
409+
function Base.checked_mul(x::FD{T,f}, y::FD{T,f}) where {T, f}
410+
powt = coefficient(FD{T, f})
411+
quotient, remainder = fldmodinline(widemul(x.i, y.i), powt)
412+
v = _round_to_nearest(quotient, remainder, powt)
413+
typemin(T) <= v <= typemax(T) || Base.Checked.throw_overflowerr_binaryop(:*, x, y)
414+
return reinterpret(FD{T, f}, T(v))
415+
end
416+
function Base.checked_div(x::FD{T,f}, y::FD{T,f}) where {T,f}
417+
C = coefficient(FD{T, f})
418+
v1 = div(promote(x.i, y.i)...)
419+
v2, b = Base.Checked.mul_with_overflow(C, v1)
420+
b && Base.Checked.throw_overflowerr_binaryop(:÷, x, y)
421+
typemin(T) <= v2 <= typemax(T) || Base.Checked.throw_overflowerr_binaryop(:÷, x, y)
422+
return reinterpret(FD{T, f}, T(v2))
423+
end
424+
425+
# --------------------------
426+
383427
Base.convert(::Type{AbstractFloat}, x::FD) = convert(floattype(typeof(x)), x)
384428
function Base.convert(::Type{TF}, x::FD{T, f}) where {TF <: AbstractFloat, T, f}
385429
convert(TF, x.i / coefficient(FD{T, f}))::TF

test/FixedDecimal.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -625,8 +625,11 @@ end
625625
end
626626

627627
@testset "limits" begin
628-
@test_throws InexactError Int8(1) / FD{Int8,2}(0.4)
629-
@test_throws InexactError FD{Int8,2}(1) / FD{Int8,2}(0.4)
628+
@test_throws OverflowError Base.checked_add(FD{Int8,2}(1), FD{Int8,2}(1))
629+
@test_throws OverflowError Base.checked_add(FD{Int8,2}(1), FD{Int8,2}(0.4))
630+
631+
@test_throws OverflowError Base.checked_div(Int8(1), FD{Int8,2}(0.4))
632+
@test_throws OverflowError Base.checked_div(FD{Int8,2}(1), FD{Int8,2}(0.4))
630633
end
631634

632635
@testset "limits of $T" for T in CONTAINER_TYPES

0 commit comments

Comments
 (0)