Skip to content

Commit

Permalink
Merge pull request #525 from petvana/simplified-mod
Browse files Browse the repository at this point in the history
Simplified version of mod(x::Interval, y::Real)
  • Loading branch information
Kolaru authored Jul 3, 2023
2 parents 4404658 + 7bef23e commit 249040d
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/IntervalArithmetic.jl
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import Base:
in, zero, one, eps, typemin, typemax, abs, abs2, real, min, max,
sqrt, exp, log, sin, cos, tan, cot, inv, cbrt, csc, hypot, sec,
exp2, exp10, log2, log10,
mod,
asin, acos, atan,
sinh, cosh, tanh, coth, csch, sech, asinh, acosh, atanh, sinpi, cospi,
union, intersect, isempty,
Expand Down
18 changes: 18 additions & 0 deletions src/intervals/functions.jl
Original file line number Diff line number Diff line change
Expand Up @@ -373,3 +373,21 @@ function nthroot(a::Interval{T}, n::Integer) where T
b = nthroot(bigequiv(a), n)
return convert(Interval{T}, b)
end

"""
Calculate `x::Interval mod y::Real` where y != zero(y) and y is not inteval`.
"""
function mod(x::Interval, y::Real)
@assert y != zero(y) """mod(x::Interval, y::Real)
is currently implemented only for a strictly positive or negative divisor y."""
division = x / y
fl = floor(division)
if !isthin(fl)
return y > zero(y) ? Interval(zero(y), y) : Interval(y, zero(y))
else
return y * (division - fl)
end
end

mod(x::Interval, y::Interval) = throw(ArgumentError("mod not defined for interval as divisor `y`"))
mod(x::Real, y::Interval) = throw(ArgumentError("mod not defined for interval as divisor `y`"))
41 changes: 41 additions & 0 deletions test/interval_tests/numeric.jl
Original file line number Diff line number Diff line change
Expand Up @@ -434,3 +434,44 @@ end
@test nthroot(Interval{BigFloat}(-81, -16), -4) ==
@test nthroot(Interval{BigFloat}(-81, -16), 1) == Interval{BigFloat}(-81, -16)
end

# approximation used for testing (not to rely on ≈ for intervals)
# ⪆(x, y) = (x ≈ y) && (x ⊇ y)
(x::Interval, y::Interval) = x.lo y.lo && x.hi y.hi && x y

@testset "`mod`" begin
r = 0.0625
x = r..(1+r)
@test mod(x, 1) == mod(x, 1.0) == 0..1
@test mod(x, 2) == mod(x, 2.0) x
@test mod(x, 2.5) x
@test mod(x, 0.5) == 0..0.5
@test mod(x, -1) == mod(x, -1.0) == -1..0
@test mod(x, -2) == mod(x, -2.0) -2+x
@test mod(x, -2.5) -2.5+x
@test mod(x, -0.5) == -0.5..0

x = (-1+r) .. -r
@test mod(x, 1) == mod(x, 1.0) 1+x
@test mod(x, 2) == mod(x, 2.0) 2+x
@test mod(x, 2.5) 2.5+x
@test mod(x, 0.5) == 0..0.5
@test mod(x, -1) == mod(x, -1.0) x
@test mod(x, -2) == mod(x, -2.0) x
@test mod(x, -2.5) x
@test mod(x, -0.5) == -0.5..0

x = -r .. 1-r
@test mod(x, 1) == mod(x, 1.0) == 0..1
@test mod(x, 2) == mod(x, 2.0) == 0..2
@test mod(x, 2.5) == 0..2.5
@test mod(x, 0.5) == 0..0.5
@test mod(x, -1) == mod(x, -1.0) == -1..0
@test mod(x, -2) == mod(x, -2.0) == -2..0
@test mod(x, -2.5) == -2.5..0
@test mod(x, -0.5) == -0.5..0

# TODO - implement mod for two intervals
@test_throws ArgumentError mod(1..2, 1.4..1.5)
@test_throws ArgumentError mod(1.0, 1.4..1.5)
end

0 comments on commit 249040d

Please sign in to comment.