Skip to content

Commit

Permalink
Fix mod1, fld1 issues. (JuliaLang#25588)
Browse files Browse the repository at this point in the history
* Fix mod1, fld1 issues, JuliaLang#20355.

* New specialization of fld1 for integers. More ambitious testing.
  • Loading branch information
GunnarFarneback authored and JeffBezanson committed Feb 24, 2018
1 parent e4b6677 commit 6239b63
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 9 deletions.
18 changes: 9 additions & 9 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -654,6 +654,8 @@ const ÷ = div
Modulus after flooring division, returning a value `r` such that `mod(r, y) == mod(x, y)`
in the range ``(0, y]`` for positive `y` and in the range ``[y,0)`` for negative `y`.
See also: [`fld1`](@ref), [`fldmod1`](@ref).
# Examples
```jldoctest
julia> mod1(4, 2)
Expand All @@ -664,16 +666,14 @@ julia> mod1(4, 3)
```
"""
mod1(x::T, y::T) where {T<:Real} = (m = mod(x, y); ifelse(m == 0, y, m))
# efficient version for integers
mod1(x::T, y::T) where {T<:Integer} = (@_inline_meta; mod(x + y - T(1), y) + T(1))


"""
fld1(x, y)
Flooring division, returning a value consistent with `mod1(x,y)`
See also: [`mod1`](@ref).
See also: [`mod1`](@ref), [`fldmod1`](@ref).
# Examples
```jldoctest
Expand All @@ -689,9 +689,11 @@ julia> x == (fld1(x, y) - 1) * y + mod1(x, y)
true
```
"""
fld1(x::T, y::T) where {T<:Real} = (m=mod(x,y); fld(x-m,y))
# efficient version for integers
fld1(x::T, y::T) where {T<:Integer} = fld(x+y-T(1),y)
fld1(x::T, y::T) where {T<:Real} = (m = mod1(x, y); fld(x + y - m, y))
function fld1(x::T, y::T) where T<:Integer
d = div(x, y)
return d + (!signbit(x y) & (d * y != x))
end

"""
fldmod1(x, y)
Expand All @@ -700,9 +702,7 @@ Return `(fld1(x,y), mod1(x,y))`.
See also: [`fld1`](@ref), [`mod1`](@ref).
"""
fldmod1(x::T, y::T) where {T<:Real} = (fld1(x,y), mod1(x,y))
# efficient version for integers
fldmod1(x::T, y::T) where {T<:Integer} = (fld1(x,y), mod1(x,y))
fldmod1(x, y) = (fld1(x, y), mod1(x, y))

conj(x) = x

Expand Down
50 changes: 50 additions & 0 deletions test/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,53 @@ Base.:(<)(x::TypeWrapper, y::TypeWrapper) = (x.t <: y.t) & (x.t != y.t)
@test TypeWrapper(Int) <= TypeWrapper(Real)
@test !(TypeWrapper(Int) <= TypeWrapper(Float64))
end

# issue #20355
@testset "mod1, fld1" begin
for T in [Int8, Int16, Int32, Int64],
x in T[typemin(T); typemin(T) + 1; -10:10; typemax(T)-1; typemax(T)],
y in T[typemin(T); typemin(T) + 1; -10:-1; 1:10; typemax(T)-1; typemax(T)]

m = mod1(x, y)
@test mod(x, y) == mod(m, y)
if y > 0
@test 0 < m <= y
else
@test y <= m < 0
end
if x == typemin(T) && y == -1
@test_throws DivideError fld1(x, y)
else
f = fld1(x, y)
@test (f - 1) * y + m == x
end
end

for T in [UInt8, UInt16, UInt32, UInt64],
x in T[0:10; typemax(T)-1; typemax(T)],
y in T[1:10; typemax(T)-1; typemax(T)]

m = mod1(x, y)
@test mod(x, y) == mod(m, y)
@test 0 < m <= y
f = fld1(x, y)
@test (f - 1) * y + m == x
end

for T in [Float32, Float64, Rational{Int64}],
x in T[k // 4 for k in -10:10],
y in T[k // 4 for k in [-10:-1; 1:10]]

m = mod1(x, y)
@test mod(x, y) == mod(m, y)
if y > 0
@test 0 < m <= y
else
@test y <= m < 0
end
f = fld1(x, y)
@test (f - 1) * y + m == x
end

@test fldmod1(4.0, 3) == fldmod1(4, 3)
end

0 comments on commit 6239b63

Please sign in to comment.