diff --git a/base/operators.jl b/base/operators.jl index ef5f523089965..0d9e6376cd43f 100644 --- a/base/operators.jl +++ b/base/operators.jl @@ -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) @@ -664,8 +666,6 @@ 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)) """ @@ -673,7 +673,7 @@ mod1(x::T, y::T) where {T<:Integer} = (@_inline_meta; mod(x + y - T(1), y) + T(1 Flooring division, returning a value consistent with `mod1(x,y)` -See also: [`mod1`](@ref). +See also: [`mod1`](@ref), [`fldmod1`](@ref). # Examples ```jldoctest @@ -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) @@ -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 diff --git a/test/operators.jl b/test/operators.jl index 31b95174df3b1..5161a2977c69a 100644 --- a/test/operators.jl +++ b/test/operators.jl @@ -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