Skip to content

Commit

Permalink
mod(n, range) for integers (#32628)
Browse files Browse the repository at this point in the history
`mod` now accepts a unit range as the second argument to easily perform offset modular arithmetic to ensure the result is inside the range
  • Loading branch information
mcabbott authored and mbauman committed Jul 24, 2019
1 parent 9daaed6 commit 2182389
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 1 deletion.
3 changes: 2 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ Standard library changes
when operating over zero-dimensional arrays ([#32122]).
* `IPAddr` subtypes now behave like scalars when used in broadcasting ([#32133]).
* `clamp` can now handle missing values ([#31066]).
* `empty` now accepts a `NamedTuple` ([#32534])
* `empty` now accepts a `NamedTuple` ([#32534]).
* `mod` now accepts a unit range as the second argument to easily perform offset modular arithmetic to ensure the result is inside the range ([#32628]).

#### Libdl

Expand Down
22 changes: 22 additions & 0 deletions base/range.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1038,3 +1038,25 @@ function +(r1::StepRangeLen{T,S}, r2::StepRangeLen{T,S}) where {T,S}
end

-(r1::StepRangeLen, r2::StepRangeLen) = +(r1, -r2)

# Modular arithmetic on ranges

"""
mod(x::Integer, r::AbstractUnitRange)
Find `y` in the range `r` such that ``x ≡ y (mod n)``, where `n = length(r)`,
i.e. `y = mod(x - first(r), n) + first(r)`.
See also: [`mod1`](@ref).
# Examples
```jldoctest
julia> mod(0, Base.OneTo(3))
3
julia> mod(3, 0:2)
0
```
"""
mod(i::Integer, r::OneTo) = mod1(i, last(r))
mod(i::Integer, r::AbstractUnitRange{<:Integer}) = mod(i-first(r), length(r)) + first(r)
15 changes: 15 additions & 0 deletions test/ranges.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1519,3 +1519,18 @@ end
@test range(1, step = big(1.0), length=10) == big(1.0):1:10
@test range(1.0, step = big(1.0), length=10) == big(1.0):1:10
end

@testset "mod with ranges" begin
for n in -10:10
@test mod(n, 0:4) == mod(n, 5)
@test mod(n, 1:5) == mod1(n, 5)
@test mod(n, 2:6) == 2 + mod(n-2, 5)
@test mod(n, Base.OneTo(5)) == mod1(n, 5)
end
@test mod(Int32(3), 1:5) == 3
@test mod(big(typemax(Int))+99, 0:4) == mod(big(typemax(Int))+99, 5)
@test_throws MethodError mod(3.141, 1:5)
@test_throws MethodError mod(3, UnitRange(1.0,5.0))
@test_throws MethodError mod(3, 1:2:7)
@test_throws DivideError mod(3, 1:0)
end

0 comments on commit 2182389

Please sign in to comment.