Skip to content

Commit

Permalink
Clean up mod1
Browse files Browse the repository at this point in the history
Implement fld1 and fldmod1.
Add test cases.
Deprecate rem1.
Simplify (the only) use case in Base.
Update documentation.
  • Loading branch information
eschnett committed Dec 3, 2015
1 parent 9eb74d4 commit f2a4255
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 8 deletions.
4 changes: 1 addition & 3 deletions base/abstractarraymath.jl
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,7 @@ function repeat{T}(A::Array{T};
# "Project" outer repetitions into inner repetitions
indices_in[t] = mod1(indices_out[t], inner_size_out[t])
# Find inner repetitions using flooring division
if inner[t] != 1
indices_in[t] = fld1(indices_in[t], inner[t])
end
indices_in[t] = fld1(indices_in[t], inner[t])
end
index_in = sub2ind(size_in, indices_in...)
R[index_out] = A[index_in]
Expand Down
9 changes: 9 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,15 @@ end
@deprecate chol(A::Number, ::Type{Val{:L}}) ctranspose(chol(A))
@deprecate chol(A::AbstractMatrix, ::Type{Val{:L}}) ctranspose(chol(A))

# Number updates

# rem1 is inconsistent for x==0: The result should both have the same
# sign as x, and should be non-zero.
function rem1{T<:Real}(x::T, y::T)
depwarn("`rem1(x,y)` is discontinued, as it cannot be defined consistently for `x==0`. Rewrite the expression using `mod1` instead.", :rem1)
rem(x-1,y)+1
end

# Filesystem module updates

@deprecate_binding FS Filesystem
Expand Down
24 changes: 23 additions & 1 deletion base/docs/helpdb.jl
Original file line number Diff line number Diff line change
Expand Up @@ -5266,6 +5266,8 @@ doc"""
%(x, y)
Remainder from Euclidean division, returning a value of the same sign as `x`, and smaller in magnitude than `y`. This value is always exact.
x == div(x,m)*m + rem(x,m)
"""
rem

Expand Down Expand Up @@ -8305,6 +8307,8 @@ doc"""
mod(x, y)
Modulus after division, returning in the range \[0,`y`), if `y` is positive, or (`y`,0\] if `y` is negative.
x == fld(x,m)*m + mod(x,m)
"""
mod

Expand Down Expand Up @@ -8460,13 +8464,31 @@ Matrix inverse
"""
inv

doc"""
fld1(x,m)
Flooring division, returning a value consistent with mod1(x,m)
x == fld(x,m)*m + mod(x,m)
x == (fld1(x,m)-1)*m + mod1(x,m)
"""
fld1

doc"""
mod1(x,m)
Modulus after division, returning in the range (0,m\]
Modulus after flooring division, returning a value in the range (0,m\]
"""
mod1

doc"""
fldmod1(x,m)
Return (fld1(x,m), mod1(x,m))
"""
fldmod1

doc"""
@assert cond [text]
Expand Down
2 changes: 2 additions & 0 deletions base/exports.jl
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,9 @@ export
factor,
factorial,
fld,
fld1,
fldmod,
fldmod1,
flipsign,
float,
tryparse,
Expand Down
11 changes: 8 additions & 3 deletions base/operators.jl
Original file line number Diff line number Diff line change
Expand Up @@ -149,10 +149,15 @@ const % = rem
.%(x::Real, y::Real) = x%y
const ÷ = div

# mod returns in [0,y) whereas mod1 returns in (0,y]
# mod returns in [0,y) or (y,0] (for negative y),
# whereas mod1 returns in (0,y] or [y,0)
mod1{T<:Real}(x::T, y::T) = (m=mod(x,y); ifelse(m==0, y, m))
rem1{T<:Real}(x::T, y::T) = rem(x-1,y)+1
fld1{T<:Real}(x::T, y::T) = fld(x-1,y)+1
fld1{T<:Real}(x::T, y::T) = (m=mod(x,y); fld(x-m,y))
fldmod1{T<:Real}(x::T, y::T) = (fld1(x,y), mod1(x,y))
# efficient version for integers
mod1{T<:Integer}(x::T, y::T) = mod(x+y-T(1),y)+T(1)
fld1{T<:Integer}(x::T, y::T) = fld(x+y-T(1),y)
fldmod1{T<:Integer}(x::T, y::T) = (fld1(x,y), mod1(x,y))

# transpose
transpose(x) = x
Expand Down
28 changes: 27 additions & 1 deletion doc/stdlib/math.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ Mathematical Operators
Modulus after division, returning in the range [0,``y``\ ), if ``y`` is positive, or (``y``\ ,0] if ``y`` is negative.

.. code-block:: julia
x == fld(x,m)*m + mod(x,m)
.. function:: mod2pi(x)

.. Docstring generated from Julia source
Expand All @@ -152,6 +156,10 @@ Mathematical Operators
Remainder from Euclidean division, returning a value of the same sign as ``x``\ , and smaller in magnitude than ``y``\ . This value is always exact.

.. code-block:: julia
x == div(x,m)*m + rem(x,m)
.. function:: divrem(x, y)

.. Docstring generated from Julia source
Expand All @@ -164,11 +172,29 @@ Mathematical Operators
The floored quotient and modulus after division. Equivalent to ``(fld(x,y), mod(x,y))``\ .

.. function:: fld1(x,m)

.. Docstring generated from Julia source
Flooring division, returning a value consistent with mod1(x,m)

.. code-block:: julia
x == fld(x,m)*m + mod(x,m)
x == (fld1(x,m)-1)*m + mod1(x,m)
.. function:: mod1(x,m)

.. Docstring generated from Julia source
Modulus after division, returning in the range (0,m]
Modulus after flooring division, returning a value in the range (0,m]

.. function:: fldmod1(x,m)

.. Docstring generated from Julia source
Return (fld1(x,m), mod1(x,m))

.. function:: rem1(x,m)

Expand Down
3 changes: 3 additions & 0 deletions test/numbers.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2530,6 +2530,9 @@ end
# test second branch, after all small primes in list have been searched
@test factor(10009 * Int128(1000000000000037)) == Dict(10009=>1,1000000000000037=>1)

@test all(x -> (m=mod1(x,3); 0<m<=3), -5:+5)
@test all(x -> x == (fld1(x,3)-1)*3 + mod1(x,3), -5:+5)
@test all(x -> fldmod1(x,3) == (fld1(x,3), mod1(x,3)), -5:+5)
#Issue #5570
@test map(x -> Int(mod1(UInt(x),UInt(5))), 0:15) == [5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5]

Expand Down

0 comments on commit f2a4255

Please sign in to comment.