Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mod(n, range) for integers #32628

Merged
merged 7 commits into from
Jul 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,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