Skip to content

Commit

Permalink
Added div and rem methods for RoundFromZero
Browse files Browse the repository at this point in the history
  • Loading branch information
jessymilare committed Sep 12, 2021
1 parent 914c4c3 commit 57cc756
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 11 deletions.
22 changes: 21 additions & 1 deletion base/div.jl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ julia> div(-5, 2, RoundNearestTiesAway)
-3
julia> div(-5, 2, RoundNearestTiesUp)
-2
julia> div(4, 3, RoundFromZero)
2
julia> div(-4, 3, RoundFromZero)
-2
```
"""
div(x, y, r::RoundingMode)
Expand Down Expand Up @@ -60,6 +64,10 @@ without any intermediate rounding.
`[0,-y)` otherwise. The result may not be exact if `x` and `y` have the same sign, and
`abs(x) < abs(y)`. See also [`RoundUp`](@ref).
- if `r == RoundFromZero`, then the result is in the interval `(-y, 0]` if `y` is positive, or
`[0, -y)` otherwise. The result may not be exact if `x` and `y` have the same sign, and
`abs(x) < abs(y)`. See also [`RoundFromZero`](@ref).
# Examples:
```jldoctest
julia> x = 9; y = 4;
Expand All @@ -83,6 +91,10 @@ rem(x, y, ::RoundingMode{:Up}) = mod(x, -y)
rem(x, y, r::RoundingMode{:Nearest}) = x - y*div(x, y, r)
rem(x::Integer, y::Integer, r::RoundingMode{:Nearest}) = divrem(x, y, r)[2]

function rem(x, y, ::typeof(RoundFromZero))
signbit(x) == signbit(y) ? rem(x, y, RoundUp) : rem(x, y, RoundDown)
end

"""
fld(x, y)
Expand Down Expand Up @@ -216,6 +228,10 @@ function divrem(x::Integer, y::Integer, rnd::typeof(RoundNearestTiesUp))
end
end

function divrem(x, y, ::typeof(RoundFromZero))
signbit(x) == signbit(y) ? divrem(x, y, RoundUp) : divrem(x, y, RoundDown)
end

"""
fldmod(x, y)
Expand Down Expand Up @@ -252,12 +268,16 @@ function div(x::Integer, y::Integer, rnd::Union{typeof(RoundNearest),
divrem(x, y, rnd)[1]
end

function div(x::Integer, y::Integer, ::typeof(RoundFromZero))
signbit(x) == signbit(y) ? div(x, y, RoundUp) : div(x, y, RoundDown)
end

# For bootstrapping purposes, we define div for integers directly. Provide the
# generic signature also
div(a::T, b::T, ::typeof(RoundToZero)) where {T<:Union{BitSigned, BitUnsigned64}} = div(a, b)
div(a::Bool, b::Bool, r::RoundingMode) = div(a, b)
# Prevent ambiguities
for rm in (RoundUp, RoundDown, RoundToZero)
for rm in (RoundUp, RoundDown, RoundToZero, RoundFromZero)
@eval div(a::Bool, b::Bool, r::$(typeof(rm))) = div(a, b)
end
function div(x::Bool, y::Bool, rnd::Union{typeof(RoundNearest),
Expand Down
23 changes: 13 additions & 10 deletions test/int.jl
Original file line number Diff line number Diff line change
Expand Up @@ -345,25 +345,28 @@ end
@testset "rounding division" begin
for x = -100:100
for y = 1:100
for rnd in (RoundNearest, RoundNearestTiesAway, RoundNearestTiesUp)
for rnd in (RoundNearest, RoundNearestTiesAway, RoundNearestTiesUp, RoundFromZero)
@test div(x,y,rnd) == round(x/y,rnd)
@test div(x,-y,rnd) == round(x/-y,rnd)
end
@test divrem(x,y,RoundFromZero) == (div(x,y,RoundFromZero), rem(x,y,RoundFromZero))
@test divrem(x,-y,RoundFromZero) == (div(x,-y,RoundFromZero), rem(x,-y,RoundFromZero))
end
end
for (a, b, nearest, away, up) in (
(3, 2, 2, 2, 2),
(5, 3, 2, 2, 2),
(-3, 2, -2, -2, -1),
(5, 2, 2, 3, 3),
(-5, 2, -2, -3, -2),
(-5, 3, -2, -2, -2),
(5, -3, -2, -2, -2))
for (a, b, nearest, away, up, from_zero) in (
(3, 2, 2, 2, 2, 2),
(5, 3, 2, 2, 2, 2),
(-3, 2, -2, -2, -1, -2),
(5, 2, 2, 3, 3, 3),
(-5, 2, -2, -3, -2, -3),
(-5, 3, -2, -2, -2, -2),
(5, -3, -2, -2, -2, -2))
for sign in (+1, -1)
(a, b) = (a*sign, b*sign)
@test div(a, b, RoundNearest) == nearest
@test div(a, b, RoundNearestTiesAway) == away
@test div(a, b, RoundNearestTiesUp) == up
@test div(a, b, RoundFromZero) == from_zero
end
end

Expand All @@ -374,7 +377,7 @@ end
@test div(typemax(Int)-2, typemax(Int), RoundNearest) == 1

# Exhaustively test (U)Int8 to catch any overflow-style issues
for r in (RoundNearest, RoundNearestTiesAway, RoundNearestTiesUp)
for r in (RoundNearest, RoundNearestTiesAway, RoundNearestTiesUp, RoundFromZero)
for T in (UInt8, Int8)
for x in typemin(T):typemax(T)
for y in typemin(T):typemax(T)
Expand Down
4 changes: 4 additions & 0 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2511,18 +2511,22 @@ end
@test rem(T(1), T(2), RoundNearest) == 1
@test rem(T(1), T(2), RoundDown) == 1
@test rem(T(1), T(2), RoundUp) == -1
@test rem(T(1), T(2), RoundFromZero) == -1
@test rem(T(1.5), T(2), RoundToZero) == 1.5
@test rem(T(1.5), T(2), RoundNearest) == -0.5
@test rem(T(1.5), T(2), RoundDown) == 1.5
@test rem(T(1.5), T(2), RoundUp) == -0.5
@test rem(T(1.5), T(2), RoundFromZero) == -0.5
@test rem(T(-1), T(2), RoundToZero) == -1
@test rem(T(-1), T(2), RoundNearest) == -1
@test rem(T(-1), T(2), RoundDown) == 1
@test rem(T(-1), T(2), RoundUp) == -1
@test rem(T(-1), T(2), RoundFromZero) == 1
@test rem(T(-1.5), T(2), RoundToZero) == -1.5
@test rem(T(-1.5), T(2), RoundNearest) == 0.5
@test rem(T(-1.5), T(2), RoundDown) == 0.5
@test rem(T(-1.5), T(2), RoundUp) == -1.5
@test rem(T(-1.5), T(2), RoundFromZero) == 0.5
end

@testset "rem for $T RoundNearest" for T in (Int8, Int16, Int32, Int64, Int128)
Expand Down

0 comments on commit 57cc756

Please sign in to comment.