diff --git a/examples/draw_function_image.jl b/examples/draw_function_image.jl index 8246f566c..2c73bb5c7 100644 --- a/examples/draw_function_image.jl +++ b/examples/draw_function_image.jl @@ -20,8 +20,10 @@ function draw(box_list::Vector{T}, color="grey", alpha=0.5) where T<:IntervalBox patch_list = [] for box in box_list x, y = box + xlo, xhi = bounds(x) + ylo, yhi = bounds(y) push!(patch_list, - make_rectangle(x.lo, y.lo, x.hi-x.lo, y.hi-y.lo, color, alpha)) + make_rectangle(xlo, ylo, xhi-xlo, yhi-ylo, color, alpha)) end ax = gca() diff --git a/src/bisect.jl b/src/bisect.jl index f7b92e782..904917497 100644 --- a/src/bisect.jl +++ b/src/bisect.jl @@ -12,7 +12,7 @@ function bisect(X::Interval, α=where_bisect) m = scaled_mid(X, α) - return (Interval(X.lo, m), Interval(m, X.hi)) + return (Interval(inf(X), m), Interval(m, sup(X))) end """ @@ -48,7 +48,7 @@ Splits `x` in `n` intervals of the same diameter, which are returned as a vector. """ function mince(x::Interval, n) - nodes = range(x.lo, x.hi, length = n+1) + nodes = range(inf(x), sup(x), length = n+1) return [Interval(nodes[i], nodes[i+1]) for i in 1:length(nodes)-1] end diff --git a/src/decorations/decorations.jl b/src/decorations/decorations.jl index 160a86432..0dc5ba053 100644 --- a/src/decorations/decorations.jl +++ b/src/decorations/decorations.jl @@ -10,5 +10,5 @@ nai(::Interval{T}) where T<:Real = nai(T) nai(::DecoratedInterval{T}) where T<:Real = nai(T) nai() = nai(Interval{default_bound()}) -isnai(x::Interval) = isnan(x.lo) || isnan(x.hi) #|| x.lo > x.hi || (isinf(x.lo) && x.lo == x.hi) +isnai(x::Interval) = isnan(inf(x)) || isnan(sup(x)) #|| inf(x) > sup(x) || (isinf(inf(x)) && inf(x) == sup(x)) isnai(x::DecoratedInterval) = isnai(interval(x)) || x.decoration == ill diff --git a/src/decorations/functions.jl b/src/decorations/functions.jl index b07975adb..a310678e2 100644 --- a/src/decorations/functions.jl +++ b/src/decorations/functions.jl @@ -107,7 +107,7 @@ function ^(xx::DecoratedInterval{T}, q::AbstractFloat) where T x = interval(xx) r = x^q d = min(decoration(xx), decoration(r)) - if x.lo > zero(T) || (x.lo ≥ zero(T) && q > zero(T)) || + if inf(x) > zero(T) || (inf(x) ≥ zero(T) && q > zero(T)) || (isinteger(q) && q > zero(q)) || (isinteger(q) && zero(T) ∉ x) return DecoratedInterval(r, d) end @@ -118,7 +118,7 @@ function ^(xx::DecoratedInterval{T}, q::Rational{S}) where {T, S<:Integer} x = interval(xx) r = x^q d = min(decoration(xx), decoration(r)) - if x.lo > zero(T) || (x.lo ≥ zero(T) && q > zero(T)) || + if inf(x) > zero(T) || (inf(x) ≥ zero(T) && q > zero(T)) || (isinteger(q) && q > zero(q)) || (isinteger(q) && zero(T) ∉ x) return DecoratedInterval(r, d) end @@ -130,9 +130,9 @@ function ^(xx::DecoratedInterval{T}, qq::DecoratedInterval{S}) where {T,S} q = interval(qq) r = x^q d = min(decoration(xx), decoration(qq), decoration(r)) - if x.lo > zero(T) || (x.lo ≥ zero(T) && q.lo > zero(T)) || - (isthin(q) && isinteger(q.lo) && q.lo > zero(q)) || - (isthin(q) && isinteger(q.lo) && zero(T) ∉ x) + if inf(x) > zero(T) || (inf(x) ≥ zero(T) && inf(q) > zero(T)) || + (isthin(q) && isinteger(inf(q)) && inf(q) > zero(q)) || + (isthin(q) && isinteger(inf(q)) && zero(T) ∉ x) return DecoratedInterval(r, d) end DecoratedInterval(r, trv) @@ -152,7 +152,7 @@ function ceil(xx::DecoratedInterval{T}) where T x = interval(xx) r = ceil(x) d = decoration(xx) - if isinteger(x.hi) + if isinteger(sup(x)) d = min(d, dac) end isthin(r) && return DecoratedInterval(r, d) @@ -162,7 +162,7 @@ function floor(xx::DecoratedInterval{T}) where T x = interval(xx) r = floor(x) d = decoration(xx) - if isinteger(x.lo) + if isinteger(inf(x)) d = min(d, dac) end isthin(r) && return DecoratedInterval(r, d) @@ -172,7 +172,7 @@ function trunc(xx::DecoratedInterval{T}) where T x = interval(xx) r = trunc(x) d = decoration(xx) - if (isinteger(x.lo) && x.lo < zero(T)) || (isinteger(x.hi) && x.hi > zero(T)) + if (isinteger(inf(x)) && inf(x) < zero(T)) || (isinteger(sup(x)) && sup(x) > zero(T)) d = min(d, dac) end isthin(r) && return DecoratedInterval(r, d) @@ -183,7 +183,7 @@ function round(xx::DecoratedInterval, ::RoundingMode{:Nearest}) x = interval(xx) r = round(x) d = decoration(xx) - if isinteger(2*x.lo) || isinteger(2*x.hi) + if isinteger(2*inf(x)) || isinteger(2*sup(x)) d = min(d, dac) end isthin(r) && return DecoratedInterval(r, d) @@ -193,7 +193,7 @@ function round(xx::DecoratedInterval, ::RoundingMode{:NearestTiesAway}) x = interval(xx) r = round(x,RoundNearestTiesAway) d = decoration(xx) - if isinteger(2*x.lo) || isinteger(2*x.hi) + if isinteger(2*inf(x)) || isinteger(2*sup(x)) d = min(d, dac) end isthin(r) && return DecoratedInterval(r, d) @@ -309,8 +309,8 @@ function atan(yy::DecoratedInterval{T}, xx::DecoratedInterval{T}) where T # Check cases when decoration is trv and decays (from com or dac) if zero(T) ∈ y zero(T) ∈ x && return DecoratedInterval(r, trv) - if x.hi < zero(T) - y.lo < zero(T) && return DecoratedInterval(r, min(d, def)) + if sup(x) < zero(T) + inf(y) < zero(T) && return DecoratedInterval(r, min(d, def)) return DecoratedInterval(r, min(d, dac)) end end diff --git a/src/decorations/intervals.jl b/src/decorations/intervals.jl index 614bae765..6c09019f9 100644 --- a/src/decorations/intervals.jl +++ b/src/decorations/intervals.jl @@ -75,8 +75,8 @@ macro decorated(ex...) if !(ex[1] isa String) if length(ex) == 1 x = :(@interval($(esc(ex[1])))) - lo = :($x.lo) - hi = :($x.hi) + lo = :(inf($x)) + hi = :(sup($x)) else lo, hi = ex end diff --git a/src/display.jl b/src/display.jl index 5ac806ca0..7db5ef803 100644 --- a/src/display.jl +++ b/src/display.jl @@ -185,16 +185,18 @@ function basic_representation(a::Interval, format=nothing) local output + alo, ahi = bounds(a) + if format == :standard - aa = round_string(a.lo, sigfigs, RoundDown) - bb = round_string(a.hi, sigfigs, RoundUp) + aa = round_string(alo, sigfigs, RoundDown) + bb = round_string(ahi, sigfigs, RoundUp) output = "[$aa, $bb]" output = replace(output, "inf" => "∞") output = replace(output, "Inf" => "∞") elseif format == :full - output = "Interval($(a.lo), $(a.hi))" + output = "Interval($(alo), $(ahi))" elseif format == :midpoint m = round_string(mid(a), sigfigs, RoundNearest) @@ -218,15 +220,17 @@ function basic_representation(a::Interval{Float32}, format=nothing) local output + alo, ahi = bounds(a) + if format == :standard - aa = round_string(a.lo, sigfigs, RoundDown) - bb = round_string(a.hi, sigfigs, RoundUp) + aa = round_string(alo, sigfigs, RoundDown) + bb = round_string(ahi, sigfigs, RoundUp) output = "[$(aa)f0, $(bb)f0]" elseif format == :full - output = "Interval($(a.lo)f0, $(a.hi)f0)" + output = "Interval($(alo)f0, $(ahi)f0)" elseif format == :midpoint m = round_string(mid(a), sigfigs, RoundNearest) @@ -252,11 +256,13 @@ function basic_representation(a::Interval{Rational{T}}, format=nothing) where local output + alo, ahi = bounds(a) + if format == :standard - output = "[$(a.lo), $(a.hi)]" + output = "[$(alo), $(ahi)]" elseif format == :full - output = "Interval($(a.lo), $(a.hi))" + output = "Interval($(alo), $(ahi))" elseif format == :midpoint m = mid(a) @@ -289,7 +295,7 @@ function representation(a::Interval{BigFloat}, format=nothing) end if format == :standard - return string(basic_representation(a, format), subscriptify(precision(a.lo))) + return string(basic_representation(a, format), subscriptify(precision(sup(a)))) else return basic_representation(a, format) end diff --git a/src/intervals/arithmetic/absmax.jl b/src/intervals/arithmetic/absmax.jl index 88a844a8a..2aa1a2dea 100644 --- a/src/intervals/arithmetic/absmax.jl +++ b/src/intervals/arithmetic/absmax.jl @@ -23,7 +23,7 @@ Implement the `min` function of the IEEE Std 1788-2015 (Table 9.1). """ function min(a::F, b::F) where {F<:Interval} (isempty(a) || isempty(b)) && return emptyinterval(F) - return F( min(a.lo, b.lo), min(a.hi, b.hi)) + return F( min(inf(a), inf(b)), min(sup(a), sup(b))) end """ @@ -33,5 +33,5 @@ Implement the `max` function of the IEEE Std 1788-2015 (Table 9.1). """ function max(a::F, b::F) where {F<:Interval} (isempty(a) || isempty(b)) && return emptyinterval(F) - return F( max(a.lo, b.lo), max(a.hi, b.hi)) + return F( max(inf(a), inf(b)), max(sup(a), sup(b))) end \ No newline at end of file diff --git a/src/intervals/arithmetic/basic.jl b/src/intervals/arithmetic/basic.jl index a1e8355ea..7f4887541 100644 --- a/src/intervals/arithmetic/basic.jl +++ b/src/intervals/arithmetic/basic.jl @@ -13,7 +13,7 @@ Implement the `neg` function of the IEEE Std 1788-2015 (Table 9.1). """ --(a::F) where {F<:Interval} = F(-a.hi, -a.lo) +-(a::F) where {F<:Interval} = F(-sup(a), -inf(a)) """ @@ -25,14 +25,14 @@ Implement the `add` function of the IEEE Std 1788-2015 (Table 9.1). """ function +(a::F, b::T) where {T, F<:Interval{T}} isempty(a) && return emptyinterval(F) - return @round(F, a.lo + b, a.hi + b) + return @round(F, inf(a) + b, sup(a) + b) end +(a::Interval{T}, b::S) where {T, S<:Real} = a + Interval{T}(b) +(b::Real, a::Interval) = a + b function +(a::F, b::F) where {F<:Interval} (isempty(a) || isempty(b)) && return emptyinterval(F) - return @round(F, a.lo + b.lo, a.hi + b.hi) + return @round(F, inf(a) + inf(b), sup(a) + sup(b)) end """ @@ -44,17 +44,17 @@ Implement the `sub` function of the IEEE Std 1788-2015 (Table 9.1). """ function -(a::F, b::T) where {T<:Real, F<:Interval{T}} isempty(a) && return emptyinterval(F) - return @round(F, a.lo - b, a.hi - b) + return @round(F, inf(a) - b, sup(a) - b) end function -(b::T, a::F) where {T, F<:Interval{T}} isempty(a) && return emptyinterval(F) - return @round(F, b - a.hi, b - a.lo) + return @round(F, b - sup(a), b - inf(a)) end function -(a::F, b::F) where {F<:Interval} (isempty(a) || isempty(b)) && return emptyinterval(F) - return @round(F, a.lo - b.hi, a.hi - b.lo) + return @round(F, inf(a) - sup(b), sup(a) - inf(b)) end -(a::F, b::Real) where {F<:Interval} = a - F(b) @@ -67,7 +67,7 @@ Multiply an interval by a positive scalar. For efficiency, does not check that the constant is positive. """ -@inline scale(α, a::F) where {F<:Interval} = @round(F, α*a.lo, α*a.hi) +@inline scale(α, a::F) where {F<:Interval} = @round(F, α*inf(a), α*sup(a)) """ *(a::Interval, b::Real) @@ -83,9 +83,9 @@ function *(x::T, a::F) where {T<:Real, F<:Interval{T}} (isthinzero(a) || iszero(x)) && return zero(F) if x ≥ 0.0 - return @round(F, a.lo*x, a.hi*x) + return @round(F, inf(a)*x, sup(a)*x) else - return @round(F, a.hi*x, a.lo*x) + return @round(F, sup(a)*x, inf(a)*x) end end @@ -111,19 +111,19 @@ function unbounded_mult(::Type{F}, x::T, y::T, r::RoundingMode) where {T, F<:Int end function mult(op, a::F, b::F) where {T, F<:Interval{T}} - if b.lo >= zero(T) - a.lo >= zero(T) && return @round(F, op(a.lo, b.lo), op(a.hi, b.hi)) - a.hi <= zero(T) && return @round(F, op(a.lo, b.hi), op(a.hi, b.lo)) - return @round(F, a.lo*b.hi, a.hi*b.hi) # when zero(T) ∈ a - elseif b.hi <= zero(T) - a.lo >= zero(T) && return @round(F, op(a.hi, b.lo), op(a.lo, b.hi)) - a.hi <= zero(T) && return @round(F, op(a.hi, b.hi), op(a.lo, b.lo)) - return @round(F, a.hi*b.lo, a.lo*b.lo) # when zero(T) ∈ a + if inf(b) >= zero(T) + inf(a) >= zero(T) && return @round(F, op(inf(a), inf(b)), op(sup(a), sup(b))) + sup(a) <= zero(T) && return @round(F, op(inf(a), sup(b)), op(sup(a), inf(b))) + return @round(F, inf(a)*sup(b), sup(a)*sup(b)) # when zero(T) ∈ a + elseif sup(b) <= zero(T) + inf(a) >= zero(T) && return @round(F, op(sup(a), inf(b)), op(inf(a), sup(b))) + sup(a) <= zero(T) && return @round(F, op(sup(a), sup(b)), op(inf(a), inf(b))) + return @round(F, sup(a)*inf(b), inf(a)*inf(b)) # when zero(T) ∈ a else - a.lo > zero(T) && return @round(F, op(a.hi, b.lo), op(a.hi, b.hi)) - a.hi < zero(T) && return @round(F, op(a.lo, b.hi), op(a.lo, b.lo)) - return @round(F, min( op(a.lo, b.hi), op(a.hi, b.lo) ), - max( op(a.lo, b.lo), op(a.hi, b.hi) )) + inf(a) > zero(T) && return @round(F, op(sup(a), inf(b)), op(sup(a), sup(b))) + sup(a) < zero(T) && return @round(F, op(inf(a), sup(b)), op(inf(a), inf(b))) + return @round(F, min( op(inf(a), sup(b)), op(sup(a), inf(b)) ), + max( op(inf(a), inf(b)), op(sup(a), sup(b)) )) end end @@ -141,9 +141,9 @@ function /(a::F, x::Real) where {F<:Interval} iszero(x) && return div_by_thin_zero(a) if x ≥ 0.0 - return @round(F, a.lo/x, a.hi/x) + return @round(F, inf(a)/x, sup(a)/x) else - return @round(F, a.hi/x, a.lo/x) + return @round(F, sup(a)/x, inf(a)/x) end end @@ -153,27 +153,27 @@ function /(a::F, b::F) where {T, F<:Interval{T}} (isempty(a) || isempty(b)) && return emptyinterval(F) isthinzero(b) && return div_by_thin_zero(a) - if b.lo > zero(T) # b strictly positive - a.lo >= zero(T) && return @round(F, a.lo/b.hi, a.hi/b.lo) - a.hi <= zero(T) && return @round(F, a.lo/b.lo, a.hi/b.hi) - return @round(F, a.lo/b.lo, a.hi/b.lo) # zero(T) ∈ a + if inf(b) > zero(T) # b strictly positive + inf(a) >= zero(T) && return @round(F, inf(a)/sup(b), sup(a)/inf(b)) + sup(a) <= zero(T) && return @round(F, inf(a)/inf(b), sup(a)/sup(b)) + return @round(F, inf(a)/inf(b), sup(a)/inf(b)) # zero(T) ∈ a - elseif b.hi < zero(T) # b strictly negative - a.lo >= zero(T) && return @round(F, a.hi/b.hi, a.lo/b.lo) - a.hi <= zero(T) && return @round(F, a.hi/b.lo, a.lo/b.hi) - return @round(F, a.hi/b.hi, a.lo/b.hi) # zero(T) ∈ a + elseif sup(b) < zero(T) # b strictly negative + inf(a) >= zero(T) && return @round(F, sup(a)/sup(b), inf(a)/inf(b)) + sup(a) <= zero(T) && return @round(F, sup(a)/inf(b), inf(a)/sup(b)) + return @round(F, sup(a)/sup(b), inf(a)/sup(b)) # zero(T) ∈ a else # b contains zero, but is not zero(b) isthinzero(a) && return a - if iszero(b.lo) - a.lo >= zero(T) && return @round(F, a.lo/b.hi, T(Inf)) - a.hi <= zero(T) && return @round(F, T(-Inf), a.hi/b.hi) + if iszero(inf(b)) + inf(a) >= zero(T) && return @round(F, inf(a)/sup(b), T(Inf)) + sup(a) <= zero(T) && return @round(F, T(-Inf), sup(a)/sup(b)) return entireinterval(F) - elseif iszero(b.hi) - a.lo >= zero(T) && return @round(F, T(-Inf), a.lo/b.lo) - a.hi <= zero(T) && return @round(F, a.hi/b.lo, T(Inf)) + elseif iszero(sup(b)) + inf(a) >= zero(T) && return @round(F, T(-Inf), inf(a)/inf(b)) + sup(a) <= zero(T) && return @round(F, sup(a)/inf(b), T(Inf)) return entireinterval(F) else @@ -194,13 +194,13 @@ function inv(a::F) where {T, F<:Interval{T}} isempty(a) && return emptyinterval(F) if zero(T) ∈ a - a.lo < zero(T) == a.hi && return @round(F, T(-Inf), inv(a.lo)) - a.lo == zero(T) < a.hi && return @round(F, inv(a.hi), T(Inf)) - a.lo < zero(T) < a.hi && return entireinterval(F) + inf(a) < zero(T) == sup(a) && return @round(F, T(-Inf), inv(inf(a))) + inf(a) == zero(T) < sup(a) && return @round(F, inv(sup(a)), T(Inf)) + inf(a) < zero(T) < sup(a) && return entireinterval(F) isthinzero(a) && return div_by_thin_zero(one(F)) end - return @round(F, inv(a.hi), inv(a.lo)) + return @round(F, inv(sup(a)), inv(inf(a))) end # Rational division @@ -233,18 +233,18 @@ function fma(a::F, b::F, c::F) where {T, F<:Interval{T}} end lo = setrounding(T, RoundDown) do - lo1 = fma(a.lo, b.lo, c.lo) - lo2 = fma(a.lo, b.hi, c.lo) - lo3 = fma(a.hi, b.lo, c.lo) - lo4 = fma(a.hi, b.hi, c.lo) + lo1 = fma(inf(a), inf(b), inf(c)) + lo2 = fma(inf(a), sup(b), inf(c)) + lo3 = fma(sup(a), inf(b), inf(c)) + lo4 = fma(sup(a), sup(b), inf(c)) min_ignore_nans(lo1, lo2, lo3, lo4) end hi = setrounding(T, RoundUp) do - hi1 = fma(a.lo, b.lo, c.hi) - hi2 = fma(a.lo, b.hi, c.hi) - hi3 = fma(a.hi, b.lo, c.hi) - hi4 = fma(a.hi, b.hi, c.hi) + hi1 = fma(inf(a), inf(b), sup(c)) + hi2 = fma(inf(a), sup(b), sup(c)) + hi3 = fma(sup(a), inf(b), sup(c)) + hi4 = fma(sup(a), sup(b), sup(c)) max_ignore_nans(hi1, hi2, hi3, hi4) end @@ -264,5 +264,5 @@ function sqrt(a::F) where {F<:Interval} isempty(a) && return a - return @round(F, sqrt(a.lo), sqrt(a.hi)) # `sqrt` is correctly-rounded + return @round(F, sqrt(inf(a)), sqrt(sup(a))) # `sqrt` is correctly-rounded end diff --git a/src/intervals/arithmetic/hyperbolic.jl b/src/intervals/arithmetic/hyperbolic.jl index 18a36522f..89345bff0 100644 --- a/src/intervals/arithmetic/hyperbolic.jl +++ b/src/intervals/arithmetic/hyperbolic.jl @@ -13,7 +13,7 @@ for f in (:sinh, :tanh, :asinh) """ function ($f)(a::F) where {F<:Interval} isempty(a) && return a - return @round(F, ($f)(a.lo), ($f)(a.hi)) + return @round(F, ($f)(inf(a)), ($f)(sup(a))) end end end @@ -39,17 +39,18 @@ function coth(a::F) where {F<:Interval} isthinzero(a) && return emptyinterval(a) - a.hi > 0 > a.lo && return entireinterval(a) + alo, ahi = bounds(a) + ahi > 0 > alo && return entireinterval(a) - if iszero(a.hi) - return @round(F, -Inf, coth(a.lo)) + if iszero(ahi) + return @round(F, -Inf, coth(alo)) - elseif a.hi > 0 && iszero(a.lo) - return @round(F, coth(a.hi), Inf) + elseif ahi > 0 && iszero(alo) + return @round(F, coth(ahi), Inf) end - res_lo, res_hi = bounds(@round(F, coth(a.hi), coth(a.lo))) + res_lo, res_hi = bounds(@round(F, coth(ahi), coth(alo))) # The IEEE Std 1788-2015 does not allow intervals like of the # form Interval(∞,∞) and Interval(-∞,-∞) for set based intervals @@ -66,16 +67,17 @@ Implement the `sech` function of the IEEE Std 1788-2015 (Table 9.1). function sech(a::F) where {F<:Interval} isempty(a) && return a - if a.lo ≥ 0 + alo, ahi = bounds(a) + if alo ≥ 0 # decreasing function - return @round(F, sech(a.hi), sech(a.lo)) + return @round(F, sech(ahi), sech(alo)) - elseif a.hi ≤ 0 + elseif ahi ≤ 0 # increasing function - return @round(F, sech(a.lo), sech(a.hi)) + return @round(F, sech(alo), sech(ahi)) else - return @round(F, min(sech(a.lo), sech(a.hi)), 1) + return @round(F, min(sech(alo), sech(ahi)), 1) end end @@ -89,17 +91,19 @@ function csch(a::F) where {F<:Interval} isthinzero(a) && return emptyinterval(a) + alo, ahi = bounds(a) + if 0 ∈ a - a.hi > 0 > a.lo && return entireinterval(a) + ahi > 0 > alo && return entireinterval(a) - if a.lo == 0 - return @round(F, csch(a.hi), Inf) + if alo == 0 + return @round(F, csch(ahi), Inf) else - return @round(F, -Inf, csch(a.lo)) + return @round(F, -Inf, csch(alo)) end end - return @round(F, csch(a.hi), csch(a.lo)) + return @round(F, csch(ahi), csch(alo)) end """ @@ -112,7 +116,8 @@ function acosh(a::F) where {F<:Interval} a = a ∩ domain isempty(a) && return a - return @round(F, acosh(a.lo), acosh(a.hi)) + alo, ahi = bounds(a) + return @round(F, acosh(alo), acosh(ahi)) end """ @@ -126,7 +131,8 @@ function atanh(a::F) where {F<:Interval} isempty(a) && return a - res_lo, res_hi = bounds(@round(F, atanh(a.lo), atanh(a.hi))) + alo, ahi = bounds(a) + res_lo, res_hi = bounds(@round(F, atanh(alo), atanh(ahi))) # The IEEE Std 1788-2015 does not allow intervals like of the # form Interval(∞,∞) and Interval(-∞,-∞) for set based intervals @@ -149,7 +155,8 @@ function acoth(a::F) where {F<:Interval} !isempty(a ∩ domain_excluded) && return entireinterval(F) - res_lo, res_hi = bounds(@round(F, acoth(a.hi), acoth(a.lo))) + alo, ahi = bounds(a) + res_lo, res_hi = bounds(@round(F, acoth(ahi), acoth(alo))) # The IEEE Std 1788-2015 does not allow intervals like of the # form Interval(∞,∞) and Interval(-∞,-∞) for set based intervals diff --git a/src/intervals/arithmetic/integer.jl b/src/intervals/arithmetic/integer.jl index 189ab516d..a291032c6 100644 --- a/src/intervals/arithmetic/integer.jl +++ b/src/intervals/arithmetic/integer.jl @@ -9,15 +9,15 @@ for f in (:sign, :ceil, :floor, :trunc) @eval begin """ $($f)(a::Interval) - + Implement the `$($f)` function of the IEEE Std 1788-2015 (Table 9.1). """ function ($f)(a::F) where {F<:Interval} isempty(a) && return emptyinterval(F) - return F(($f)(a.lo), ($f)(a.hi)) + return F(($f)(inf(a)), ($f)(sup(a))) end end -end +end # NOTE this is note strictly needed as per the standard. It is documented # in the docstring of round and could be removed @@ -41,10 +41,10 @@ round(a::Interval, ::RoundingMode{:Down}) = floor(a) function round(a::F, ::RoundingMode{:Nearest}) where {F<:Interval} isempty(a) && return emptyinterval(F) - return F(round(a.lo), round(a.hi)) + return F(round(inf(a)), round(sup(a))) end function round(a::F, ::RoundingMode{:NearestTiesAway}) where {F<:Interval} isempty(a) && return emptyinterval(F) - return F(round(a.lo, RoundNearestTiesAway), round(a.hi, RoundNearestTiesAway)) + return F(round(inf(a), RoundNearestTiesAway), round(sup(a), RoundNearestTiesAway)) end diff --git a/src/intervals/arithmetic/power.jl b/src/intervals/arithmetic/power.jl index df345987d..5ba05e048 100644 --- a/src/intervals/arithmetic/power.jl +++ b/src/intervals/arithmetic/power.jl @@ -45,17 +45,17 @@ function ^(a::F, n::Integer) where {F<:Interval{BigFloat}} if isodd(n) # odd power isentire(a) && return a if n > 0 - iszero(a.lo) && return @round(F, 0, a.hi^n) - iszero(a.hi) && return @round(F, a.lo^n, 0) - return @round(F, a.lo^n, a.hi^n) + iszero(inf(a)) && return @round(F, 0, sup(a)^n) + iszero(sup(a)) && return @round(F, inf(a)^n, 0) + return @round(F, inf(a)^n, sup(a)^n) else - if a.lo ≥ 0 - iszero(a.lo) && return @round(F, a.hi^n, Inf) - return @round(F, a.hi^n, a.lo^n) + if inf(a) ≥ 0 + iszero(inf(a)) && return @round(F, sup(a)^n, Inf) + return @round(F, sup(a)^n, inf(a)^n) - elseif a.hi ≤ 0 - iszero(a.hi) && return @round(F, -Inf, a.lo^n) - return @round(F, a.hi^n, a.lo^n) + elseif sup(a) ≤ 0 + iszero(sup(a)) && return @round(F, -Inf, inf(a)^n) + return @round(F, sup(a)^n, inf(a)^n) else return entireinterval(a) end @@ -63,19 +63,19 @@ function ^(a::F, n::Integer) where {F<:Interval{BigFloat}} else # even power if n > 0 - if a.lo ≥ 0 - return @round(F, a.lo^n, a.hi^n) - elseif a.hi ≤ 0 - return @round(F, a.hi^n, a.lo^n) + if inf(a) ≥ 0 + return @round(F, inf(a)^n, sup(a)^n) + elseif sup(a) ≤ 0 + return @round(F, sup(a)^n, inf(a)^n) else return @round(F, mig(a)^n, mag(a)^n) end else - if a.lo ≥ 0 - return @round(F, a.hi^n, a.lo^n) - elseif a.hi ≤ 0 - return @round(F, a.lo^n, a.hi^n) + if inf(a) ≥ 0 + return @round(F, sup(a)^n, inf(a)^n) + elseif sup(a) ≤ 0 + return @round(F, inf(a)^n, sup(a)^n) else return @round(F, mag(a)^n, mig(a)^n) end @@ -100,17 +100,17 @@ function ^(a::F, x::BigFloat) where {F<:Interval{BigFloat}} xx = F(x) - lo = @round(F, a.lo^xx.lo, a.lo^xx.lo) - lo = (lo.lo == Inf) ? F(prevfloat(Inf), Inf) : lo + lo = @round(F, inf(a)^inf(xx), inf(a)^inf(xx)) + lo = (inf(lo) == Inf) ? F(prevfloat(Inf), Inf) : lo - lo1 = @round(F, a.lo^xx.hi, a.lo^xx.hi) - lo1 = (lo1.lo == Inf) ? F(prevfloat(Inf), Inf) : lo1 + lo1 = @round(F, inf(a)^sup(xx), inf(a)^sup(xx)) + lo1 = (inf(lo1) == Inf) ? F(prevfloat(Inf), Inf) : lo1 - hi = @round(F, a.hi^xx.lo, a.hi^xx.lo) - hi = (hi.lo == Inf) ? F(prevfloat(Inf), Inf) : hi + hi = @round(F, sup(a)^inf(xx), sup(a)^inf(xx)) + hi = (inf(hi) == Inf) ? F(prevfloat(Inf), Inf) : hi - hi1 = @round(F, a.hi^xx.hi, a.hi^xx.hi) - hi1 = (hi1.lo == Inf) ? F(prevfloat(Inf), Inf) : hi1 + hi1 = @round(F, sup(a)^sup(xx), sup(a)^sup(xx)) + hi1 = (inf(hi1) == Inf) ? F(prevfloat(Inf), Inf) : hi1 lo = hull(lo, lo1) hi = hull(hi, hi1) @@ -119,7 +119,7 @@ function ^(a::F, x::BigFloat) where {F<:Interval{BigFloat}} end function ^(a::Interval{Rational{T}}, x::AbstractFloat) where {T<:Integer} - a = Interval{Float64}(a.lo.num/a.lo.den, a.hi.num/a.hi.den) + a = Interval{Float64}(inf(a).num/inf(a).den, sup(a).num/sup(a).den) return F(a^x) end @@ -188,12 +188,12 @@ function ^(a::F, x::Interval) where {F<:Interval{BigFloat}} (isempty(x) || isempty(a)) && return emptyinterval(F) - lo1 = a^x.lo - lo2 = a^x.hi + lo1 = a^inf(x) + lo2 = a^sup(x) lo1 = hull(lo1, lo2) - hi1 = a^x.lo - hi2 = a^x.hi + hi1 = a^inf(x) + hi2 = a^sup(x) hi1 = hull(hi1, hi2) return hull(lo1, hi1) @@ -229,20 +229,20 @@ function pow(x::F, n::Integer) where {F<:Interval} Base.power_by_squaring(F(mag(x)), n) ) else - return hull( Base.power_by_squaring(F(x.lo), n), - Base.power_by_squaring(F(x.hi), n) ) + return hull( Base.power_by_squaring(F(inf(x)), n), + Base.power_by_squaring(F(sup(x)), n) ) end end function pow(x::Interval, y::Interval) # fast real power, including for y an Interval isempty(x) && return x - isthininteger(y) && return pow(x, Int(y.lo)) + isthininteger(y) && return pow(x, Int(inf(y))) return exp(y * log(x)) end function pow(x::Interval, y) # fast real power, including for y an Interval isempty(x) && return x - isinteger(y) && return pow(x, Int(y.lo)) + isinteger(y) && return pow(x, Int(inf(y))) return exp(y * log(x)) end @@ -250,7 +250,7 @@ for f in (:exp, :expm1) @eval begin function ($f)(a::F) where {F<:Interval} isempty(a) && return a - return @round( F, ($f)(a.lo), ($f)(a.hi) ) + return @round( F, ($f)(inf(a)), ($f)(sup(a)) ) end end end @@ -267,7 +267,7 @@ for f in (:exp2, :exp10, :cbrt) @eval function ($f)(a::F) where {F<:Interval{BigFloat}} isempty(a) && return a - return @round( F, ($f)(a.lo), ($f)(a.hi) ) + return @round( F, ($f)(inf(a)), ($f)(sup(a)) ) end end @@ -276,9 +276,9 @@ for f in (:log, :log2, :log10) domain = F(0, Inf) a = a ∩ domain - (isempty(a) || a.hi ≤ zero(T)) && return emptyinterval(F) + (isempty(a) || sup(a) ≤ zero(T)) && return emptyinterval(F) - return @round( F, ($f)(a.lo), ($f)(a.hi) ) + return @round( F, ($f)(inf(a)), ($f)(sup(a)) ) end end @@ -286,9 +286,9 @@ function log1p(a::F) where {T, F<:Interval{T}} domain = Interval{T}(-1, Inf) a = a ∩ domain - (isempty(a) || a.hi ≤ -one(T)) && return emptyinterval(a) + (isempty(a) || sup(a) ≤ -one(T)) && return emptyinterval(a) - @round( F, log1p(a.lo), log1p(a.hi) ) + @round( F, log1p(inf(a)), log1p(sup(a)) ) end """ diff --git a/src/intervals/arithmetic/signbit.jl b/src/intervals/arithmetic/signbit.jl index f458b1673..66209dfaf 100644 --- a/src/intervals/arithmetic/signbit.jl +++ b/src/intervals/arithmetic/signbit.jl @@ -15,9 +15,10 @@ julia> signbit(@interval(-4,5)) [0, 1] ``` """ -function signbit(a::Interval) +function signbit(a::Interval) isempty(a) && return emptyinterval(a) - return Interval(signbit(a.hi), signbit(a.lo)) + alo, ahi = bounds(a) + return interval(signbit(ahi), signbit(alo)) end for Typ in (:Interval, :Real, :Float64, :Float32, :Signed, :Unsigned) diff --git a/src/intervals/arithmetic/trigonometric.jl b/src/intervals/arithmetic/trigonometric.jl index 68057930d..13b302e10 100644 --- a/src/intervals/arithmetic/trigonometric.jl +++ b/src/intervals/arithmetic/trigonometric.jl @@ -11,8 +11,8 @@ half_pi(::Type{F}) where {F<:Interval} = scale(0.5, F(π)) two_pi(::Type{F}) where {F<:Interval} = scale(2, F(π)) function range_atan(::Type{F}) where {F<:Interval} - temp = F(π) # Using F(-π, π) converts -π to Float64 before Interval construction - return F(-temp.hi, temp.hi) + temp = sup(F(π)) # Using F(-π, π) converts -π to Float64 before Interval construction + return F(-temp, temp) end half_range_atan(::Type{F}) where {F<:Interval} = range_atan(F) / 2 @@ -31,7 +31,7 @@ Tucker, *Validated Numerics*. """ function find_quadrants(::Type{F}, x) where {F<:Interval} temp = F(x) / half_pi(F) - return floor(temp.lo), floor(temp.hi) + return floor(inf(temp)), floor(sup(temp)) end # Quadrant function for Float64 specialized methods @@ -55,12 +55,13 @@ function sin(a::F) where {F<:Interval} whole_range = F(-1, 1) - diam(a) > two_pi(F).lo && return whole_range + diam(a) > inf(two_pi(F)) && return whole_range # The following is equiavlent to doing temp = a / half_pi and - # taking floor(a.lo), floor(a.hi) - lo_quadrant = minimum(find_quadrants(F, a.lo)) - hi_quadrant = maximum(find_quadrants(F, a.hi)) + # taking floor(inf(a)), floor(sup(a)) + alo, ahi = bounds(a) + lo_quadrant = minimum(find_quadrants(F, alo)) + hi_quadrant = maximum(find_quadrants(F, ahi)) if hi_quadrant - lo_quadrant > 4 # close to limits return whole_range @@ -71,22 +72,22 @@ function sin(a::F) where {F<:Interval} # Different cases depending on the two quadrants: if lo_quadrant == hi_quadrant - a.hi - a.lo > F(π).lo && return whole_range # in same quadrant but separated by almost 2pi - lo = @round(F, sin(a.lo), sin(a.lo)) - hi = @round(F, sin(a.hi), sin(a.hi)) + ahi - alo > inf(F(π)) && return whole_range # in same quadrant but separated by almost 2pi + lo = @round(F, sin(alo), sin(alo)) + hi = @round(F, sin(ahi), sin(ahi)) return hull(lo, hi) elseif lo_quadrant == 3 && iszero(hi_quadrant) - return @round(F, sin(a.lo), sin(a.hi)) + return @round(F, sin(alo), sin(ahi)) elseif lo_quadrant == 1 && hi_quadrant == 2 - return @round(F, sin(a.hi), sin(a.lo)) + return @round(F, sin(ahi), sin(alo)) elseif ( iszero(lo_quadrant) || lo_quadrant == 3 ) && ( hi_quadrant == 1 || hi_quadrant == 2 ) - return @round(F, min(sin(a.lo), sin(a.hi)), 1) + return @round(F, min(sin(alo), sin(ahi)), 1) elseif ( lo_quadrant == 1 || lo_quadrant == 2 ) && ( hi_quadrant == 3 || iszero(hi_quadrant) ) - return @round(F, -1, max(sin(a.lo), sin(a.hi))) + return @round(F, -1, max(sin(alo), sin(ahi))) else # if( iszero(lo_quadrant) && hi_quadrant == 3 ) || ( lo_quadrant == 2 && hi_quadrant == 1 ) return whole_range @@ -98,16 +99,17 @@ function sin(a::F) where {F<:Interval{Float64}} whole_range = F(-1, 1) - diam(a) > two_pi(F).lo && return whole_range + diam(a) > inf(two_pi(F)) && return whole_range - lo_quadrant, lo = quadrant(a.lo) - hi_quadrant, hi = quadrant(a.hi) + alo, ahi = bounds(a) + lo_quadrant, lo = quadrant(alo) + hi_quadrant, hi = quadrant(ahi) - lo, hi = a.lo, a.hi # should be able to use the modulo version of a, but doesn't seem to work + lo, hi = alo, ahi # should be able to use the modulo version of a, but doesn't seem to work # Different cases depending on the two quadrants: if lo_quadrant == hi_quadrant - a.hi - a.lo > F(π).lo && return whole_range # + ahi - alo > inf(F(π)) && return whole_range # if lo_quadrant == 1 || lo_quadrant == 2 # negative slope @@ -149,10 +151,11 @@ function cos(a::F) where {F<:Interval} whole_range = F(-1, 1) - diam(a) > two_pi(F).lo && return whole_range + diam(a) > inf(two_pi(F)) && return whole_range - lo_quadrant = minimum(find_quadrants(F, a.lo)) - hi_quadrant = maximum(find_quadrants(F, a.hi)) + alo, ahi = bounds(a) + lo_quadrant = minimum(find_quadrants(F, alo)) + hi_quadrant = maximum(find_quadrants(F, ahi)) if hi_quadrant - lo_quadrant > 4 # close to limits return whole_range @@ -163,22 +166,22 @@ function cos(a::F) where {F<:Interval} # Different cases depending on the two quadrants: if lo_quadrant == hi_quadrant # Interval limits in the same quadrant - a.hi - a.lo > F(π).lo && return whole_range - lo = @round(F, cos(a.lo), cos(a.lo)) - hi = @round(F, cos(a.hi), cos(a.hi)) + ahi - alo > inf(F(π)) && return whole_range + lo = @round(F, cos(alo), cos(alo)) + hi = @round(F, cos(ahi), cos(ahi)) return hull(lo, hi) elseif lo_quadrant == 2 && hi_quadrant == 3 - return @round(F, cos(a.lo), cos(a.hi)) + return @round(F, cos(alo), cos(ahi)) elseif iszero(lo_quadrant) && hi_quadrant == 1 - return @round(F, cos(a.hi), cos(a.lo)) + return @round(F, cos(ahi), cos(alo)) elseif ( lo_quadrant == 2 || lo_quadrant == 3 ) && ( iszero(hi_quadrant) || hi_quadrant == 1 ) - return @round(F, min(cos(a.lo), cos(a.hi)), 1) + return @round(F, min(cos(alo), cos(ahi)), 1) elseif ( iszero(lo_quadrant) || lo_quadrant == 1 ) && ( hi_quadrant == 2 || hi_quadrant == 3 ) - return @round(F, -1, max(cos(a.lo), cos(a.hi))) + return @round(F, -1, max(cos(alo), cos(ahi))) else # if ( lo_quadrant == 3 && hi_quadrant == 2 ) || ( lo_quadrant == 1 && iszero(hi_quadrant) ) return whole_range @@ -190,16 +193,17 @@ function cos(a::F) where {F<:Interval{Float64}} whole_range = F(-1, 1) - diam(a) > two_pi(F).lo && return whole_range + diam(a) > inf(two_pi(F)) && return whole_range - lo_quadrant, lo = quadrant(a.lo) - hi_quadrant, hi = quadrant(a.hi) + alo, ahi = bounds(a) + lo_quadrant, lo = quadrant(alo) + hi_quadrant, hi = quadrant(ahi) - lo, hi = a.lo, a.hi + lo, hi = alo, ahi # should be able to use the modulo version of a, but doesn't seem to work # Different cases depending on the two quadrants: if lo_quadrant == hi_quadrant # Interval limits in the same quadrant - a.hi - a.lo > F(π).lo && return whole_range + ahi - alo > inf(F(π)) && return whole_range if lo_quadrant == 2 || lo_quadrant == 3 # positive slope @@ -209,16 +213,16 @@ function cos(a::F) where {F<:Interval{Float64}} end elseif lo_quadrant == 2 && hi_quadrant == 3 - return @round(F, cos(a.lo), cos(a.hi)) + return @round(F, cos(lo), cos(hi)) elseif iszero(lo_quadrant) && hi_quadrant == 1 - return @round(F, cos(a.hi), cos(a.lo)) + return @round(F, cos(hi), cos(lo)) elseif ( lo_quadrant == 2 || lo_quadrant == 3 ) && ( iszero(hi_quadrant) || hi_quadrant == 1 ) - return @round(F, min(cos(a.lo), cos(a.hi)), 1) + return @round(F, min(cos(lo), cos(hi)), 1) elseif ( iszero(lo_quadrant) || lo_quadrant == 1 ) && ( hi_quadrant == 2 || hi_quadrant == 3 ) - return @round(F, -1, max(cos(a.lo), cos(a.hi))) + return @round(F, -1, max(cos(lo), cos(hi))) else #if ( lo_quadrant == 3 && hi_quadrant == 2 ) || ( lo_quadrant == 1 && iszero(hi_quadrant) ) return whole_range @@ -239,10 +243,11 @@ Implement the `tan` function of the IEEE Std 1788-2015 (Table 9.1). function tan(a::F) where {F<:Interval} isempty(a) && return a - diam(a) > F(π).lo && return entireinterval(a) + diam(a) > inf(F(π)) && return entireinterval(a) - lo_quadrant = minimum(find_quadrants(F, a.lo)) - hi_quadrant = maximum(find_quadrants(F, a.hi)) + alo, ahi = bounds(a) + lo_quadrant = minimum(find_quadrants(F, alo)) + hi_quadrant = maximum(find_quadrants(F, ahi)) lo_quadrant_mod = mod(lo_quadrant, 2) hi_quadrant_mod = mod(hi_quadrant, 2) @@ -258,16 +263,17 @@ function tan(a::F) where {F<:Interval} return entireinterval(F) end - return @round(F, tan(a.lo), tan(a.hi)) + return @round(F, tan(alo), tan(ahi)) end function tan(a::F) where {F<:Interval{Float64}} isempty(a) && return a - diam(a) > F(π).lo && return entireinterval(a) + diam(a) > inf(F(π)) && return entireinterval(a) - lo_quadrant, lo = quadrant(a.lo) - hi_quadrant, hi = quadrant(a.hi) + alo, ahi = bounds(a) + lo_quadrant, lo = quadrant(alo) + hi_quadrant, hi = quadrant(ahi) lo_quadrant_mod = mod(lo_quadrant, 2) hi_quadrant_mod = mod(hi_quadrant, 2) @@ -281,7 +287,7 @@ function tan(a::F) where {F<:Interval{Float64}} end - return @round(F, tan(a.lo), tan(a.hi)) + return @round(F, tan(alo), tan(ahi)) end """ @@ -292,32 +298,33 @@ Implement the `cot` function of the IEEE Std 1788-2015 (Table 9.1). function cot(a::F) where {F<:Interval} isempty(a) && return a - diam(a) > F(π).lo && return entireinterval(a) + diam(a) > inf(F(π)) && return entireinterval(a) isthinzero(a) && return emptyinterval(a) - lo_quadrant = minimum(find_quadrants(F, a.lo)) - hi_quadrant = maximum(find_quadrants(F, a.hi)) + alo, ahi = bounds(a) + lo_quadrant = minimum(find_quadrants(F, alo)) + hi_quadrant = maximum(find_quadrants(F, ahi)) lo_quadrant = mod(lo_quadrant, 4) hi_quadrant = mod(hi_quadrant, 4) # Different cases depending on the two quadrants: if lo_quadrant == hi_quadrant - iszero(a.lo) && return @round(F, cot(a.hi), Inf) + iszero(alo) && return @round(F, cot(ahi), Inf) - return @round(F, cot(a.hi), cot(a.lo)) + return @round(F, cot(ahi), cot(alo)) elseif (lo_quadrant == 3 && iszero(hi_quadrant)) || (lo_quadrant == 1 && hi_quadrant ==2) - iszero(a.hi) && return @round(F, -Inf, cot(a.lo)) + iszero(ahi) && return @round(F, -Inf, cot(alo)) return entireinterval(a) elseif (iszero(lo_quadrant) && hi_quadrant == 1) || (lo_quadrant == 2 && hi_quadrant == 3) - return @round(F, cot(a.hi), cot(a.lo)) + return @round(F, cot(ahi), cot(alo)) elseif ( lo_quadrant == 2 && iszero(hi_quadrant)) - iszero(a.hi) && return @round(F, -Inf, cot(a.lo)) + iszero(ahi) && return @round(F, -Inf, cot(alo)) return entireinterval(a) @@ -338,28 +345,29 @@ Implement the `sec` function of the IEEE Std 1788-2015 (Table 9.1). function sec(a::F) where {F<:Interval} isempty(a) && return a - diam(a) > F(π).lo && return entireinterval(a) + diam(a) > inf(F(π)) && return entireinterval(a) - lo_quadrant = minimum(find_quadrants(F, a.lo)) - hi_quadrant = maximum(find_quadrants(F, a.hi)) + alo, ahi = bounds(a) + lo_quadrant = minimum(find_quadrants(F, alo)) + hi_quadrant = maximum(find_quadrants(F, ahi)) lo_quadrant = mod(lo_quadrant, 4) hi_quadrant = mod(hi_quadrant, 4) # Different cases depending on the two quadrants: if lo_quadrant == hi_quadrant # Interval limits in the same quadrant - lo = @round(F, sec(a.lo), sec(a.lo)) - hi = @round(F, sec(a.hi), sec(a.hi)) + lo = @round(F, sec(alo), sec(alo)) + hi = @round(F, sec(ahi), sec(ahi)) return hull(lo, hi) elseif (iszero(lo_quadrant) && hi_quadrant == 1) || (lo_quadrant == 2 && hi_quadrant ==3) return entireinterval(a) elseif lo_quadrant == 3 && iszero(hi_quadrant) - return @round(F, 1, max(sec(a.lo), sec(a.hi))) + return @round(F, 1, max(sec(alo), sec(ahi))) elseif lo_quadrant == 1 && hi_quadrant == 2 - return @round(F, min(sec(a.lo), sec(a.hi)), -1) + return @round(F, min(sec(alo), sec(ahi)), -1) else return entireinterval(a) @@ -378,37 +386,38 @@ Implement the `csc` function of the IEEE Std 1788-2015 (Table 9.1). function csc(a::F) where {F<:Interval} isempty(a) && return a - diam(a) > F(π).lo && return entireinterval(a) + diam(a) > inf(F(π)) && return entireinterval(a) isthinzero(a) && return emptyinterval(a) - lo_quadrant = minimum(find_quadrants(F, a.lo)) - hi_quadrant = maximum(find_quadrants(F, a.hi)) + alo, ahi = bounds(a) + lo_quadrant = minimum(find_quadrants(F, alo)) + hi_quadrant = maximum(find_quadrants(F, ahi)) lo_quadrant = mod(lo_quadrant, 4) hi_quadrant = mod(hi_quadrant, 4) # Different cases depending on the two quadrants: if lo_quadrant == hi_quadrant - iszero(a.lo) && return @round(F, csc(a.hi), Inf) + iszero(alo) && return @round(F, csc(ahi), Inf) - lo = @round(F, csc(a.lo), csc(a.lo)) - hi = @round(F, csc(a.hi), csc(a.hi)) + lo = @round(F, csc(alo), csc(alo)) + hi = @round(F, csc(ahi), csc(ahi)) return hull(lo, hi) elseif (lo_quadrant == 3 && iszero(hi_quadrant)) || (lo_quadrant == 1 && hi_quadrant ==2) - iszero(a.hi) && return @round(F, -Inf, csc(a.lo)) + iszero(ahi) && return @round(F, -Inf, csc(alo)) return entireinterval(a) elseif iszero(lo_quadrant) && hi_quadrant == 1 - return @round(F, 1, max(csc(a.lo), csc(a.hi))) + return @round(F, 1, max(csc(alo), csc(ahi))) elseif lo_quadrant == 2 && hi_quadrant == 3 - return @round(F, min(csc(a.lo), csc(a.hi)), -1) + return @round(F, min(csc(alo), csc(ahi)), -1) elseif ( lo_quadrant == 2 && iszero(hi_quadrant)) - iszero(a.hi) && return @round(F, -Inf, -1) + iszero(ahi) && return @round(F, -Inf, -1) return entireinterval(a) @@ -434,7 +443,8 @@ function asin(a::F) where {F<:Interval} isempty(a) && return a - return @round(F, asin(a.lo), asin(a.hi)) + alo, ahi = bounds(a) + return @round(F, asin(alo), asin(ahi)) end """ @@ -448,7 +458,8 @@ function acos(a::F) where {F<:Interval} isempty(a) && return a - return @round(F, acos(a.hi), acos(a.lo)) + alo, ahi = bounds(a) + return @round(F, acos(ahi), acos(alo)) end """ @@ -459,7 +470,8 @@ Implement the `atan` function of the IEEE Std 1788-2015 (Table 9.1). function atan(a::F) where {F<:Interval} isempty(a) && return a - return @round(F, atan(a.lo), atan(a.hi)) + alo, ahi = bounds(a) + return @round(F, atan(alo), atan(ahi)) end function atan(y::Interval{T}, x::Interval{S}) where {T, S} @@ -474,55 +486,63 @@ function atan(y::Interval{BigFloat}, x::Interval{BigFloat}) (isempty(y) || isempty(x)) && return emptyinterval(F) + ylo, yhi = bounds(y) + xlo, xhi = bounds(x) + z = zero(T) + # Prevent nonsense results when y has a signed zero: - if iszero(y.lo) - y = F(0, y.hi) + if iszero(ylo) + y = F(0, yhi) end - if iszero(y.hi) - y = F(y.lo, 0) + if iszero(yhi) + y = F(ylo, 0) end # Check cases based on x if isthinzero(x) isthinzero(y) && return emptyinterval(F) - y.lo ≥ zero(T) && return half_pi(F) - y.hi ≤ zero(T) && return -half_pi(F) + ylo ≥ z && return half_pi(F) + yhi ≤ z && return -half_pi(F) return half_range_atan(F) - elseif x.lo > zero(T) + elseif xlo > z isthinzero(y) && return y - y.lo ≥ zero(T) && - return @round(F, atan(y.lo, x.hi), atan(y.hi, x.lo)) # refinement lo bound - y.hi ≤ zero(T) && - return @round(F, atan(y.lo, x.lo), atan(y.hi, x.hi)) - return @round(F, atan(y.lo, x.lo), atan(y.hi, x.lo)) + ylo ≥ z && + return @round(F, atan(ylo, xhi), atan(yhi, xlo)) # refinement lo bound + yhi ≤ z && + return @round(F, atan(ylo, xlo), atan(yhi, xhi)) + return @round(F, atan(ylo, xlo), atan(yhi, xlo)) - elseif x.hi < zero(T) + elseif xhi < z isthinzero(y) && return F(π) - y.lo ≥ zero(T) && - return @round(F, atan(y.hi, x.hi), atan(y.lo, x.lo)) - y.hi < zero(T) && - return @round(F, atan(y.hi, x.lo), atan(y.lo, x.hi)) + ylo ≥ z && + return @round(F, atan(yhi, xhi), atan(ylo, xlo)) + yhi < z && + return @round(F, atan(yhi, xlo), atan(ylo, xhi)) return range_atan(F) - else # zero(T) ∈ x - if iszero(x.lo) + else # z ∈ x + if iszero(xlo) isthinzero(y) && return y - y.lo ≥ zero(T) && return @round(F, atan(y.lo, x.hi), half_range_atan(F).hi) - y.hi ≤ zero(T) && return @round(F, half_range_atan(F).lo, atan(y.hi, x.hi)) + ylo ≥ z && + return F(atan(ylo, xhi, RoundDown), sup(half_range_atan(F))) + yhi ≤ z && + return F(inf(half_range_atan(F)), atan(yhi, xhi, RoundUp)) return half_range_atan(F) - elseif iszero(x.hi) + elseif iszero(xhi) isthinzero(y) && return F(π) - y.lo ≥ zero(T) && return @round(F, half_pi(F).lo, atan(y.lo, x.lo)) - y.hi < zero(T) && return @round(F, atan(y.hi, x.lo), -(half_pi(F).lo)) + ylo ≥ z && + return F(inf(half_pi(F)), atan(ylo, xlo, RoundUp)) + yhi < z && + return F(atan(yhi, xlo, RoundDown), inf(-half_pi(F))) return range_atan(F) else - y.lo ≥ zero(T) && - return @round(F, atan(y.lo, x.hi), atan(y.lo, x.lo)) - y.hi < zero(T) && - return @round(F, atan(y.hi, x.lo), atan(y.hi, x.hi)) + ylo ≥ z && + return @round(F, atan(ylo, xhi), atan(ylo, xlo)) + yhi < z && + return @round(F, atan(yhi, xlo), atan(yhi, xhi)) return range_atan(F) end end @@ -536,6 +556,6 @@ Implement the `acot` function of the IEEE Std 1788-2015 (Table 9.1). function acot(a::F) where {F<:Interval} isempty(a) && return a - return atomic(F, Interval(acot(bigequiv(a.hi)), acot(bigequiv(a.lo)))) - # return atomic(F, @round(Interval{BigFloat}, acot(bigequiv(a.hi)), acot(bigequiv(a.lo)))) + return atomic(F, Interval(acot(bigequiv(sup(a))), acot(bigequiv(inf(a))))) + # return atomic(F, @round(Interval{BigFloat}, acot(bigequiv(sup(a))), acot(bigequiv(inf(a))))) end diff --git a/src/intervals/construction.jl b/src/intervals/construction.jl index 0f3e98e77..51fdd2739 100644 --- a/src/intervals/construction.jl +++ b/src/intervals/construction.jl @@ -101,7 +101,7 @@ end #= Interval =# Interval{T}(x::Interval{T}) where T = x -Interval{T}(x::Interval) where T = Interval{T}(x.lo, x.hi) +Interval{T}(x::Interval) where T = Interval{T}(inf(x), sup(x)) #= Complex =# Interval(x::Complex) = Interval(real(x)) + im*Interval(imag(x)) @@ -180,7 +180,7 @@ Despite using the center-radius notation for its creation, the interval is still represented by its bounds internally. """ a ± b = checked_interval(-(a, b, RoundDown), +(a, b, RoundUp)) -±(a::Interval, b) = Interval(-(a.lo, b, RoundDown), +(a.hi, b, RoundUp)) +±(a::Interval, b) = Interval(-(inf(a), b, RoundDown), +(sup(a), b, RoundUp)) """ atomic(::Type{<:Interval}, x) diff --git a/src/intervals/interval_operations/boolean.jl b/src/intervals/interval_operations/boolean.jl index 5e039ba53..33204c820 100644 --- a/src/intervals/interval_operations/boolean.jl +++ b/src/intervals/interval_operations/boolean.jl @@ -3,7 +3,7 @@ #= This file contains the functions described in sections 9.5 of the IEEE Std 1788-2015 (Boolean functions of intervals) and/or required for set-based flavor in section 10.5.9. - + Some other (non required) related functions are also present, as well as some of the "Recommended operations" (section 10.6.3). =# @@ -30,7 +30,7 @@ In most case this is equivalent to the built-in `===`. """ function ≛(a::Interval, b::Interval) isempty(a) && isempty(b) && return true - return a.lo == b.lo && a.hi == b.hi + return inf(a) == inf(b) && sup(a) == sup(b) end """ @@ -39,7 +39,7 @@ end Check if the interval `a` contains exactly (and only) the number `x`. """ function ≛(a::Interval, x::Real) - a.lo == a.hi == x && return true + inf(a) == sup(a) == x && return true return false end @@ -54,7 +54,7 @@ Implement the `subset` function of the IEEE Std 1788-2015 (Table 9.3). """ function ⊆(a::Interval, b::Interval) isempty(a) && return true - b.lo ≤ a.lo && a.hi ≤ b.hi + inf(b) ≤ inf(a) && sup(a) ≤ sup(b) end """ @@ -82,10 +82,10 @@ any element of `b`. Implement the `less` function of the IEEE Std 1788-2015 (Table 10.3). """ -function isweaklyless(a::F, b::F) where {F<:Interval} +function isweaklyless(a::Interval, b::Interval) isempty(a) && isempty(b) && return true (isempty(a) || isempty(b)) && return false - (a.lo ≤ b.lo) && (a.hi ≤ b.hi) + (inf(a) ≤ inf(b)) && (sup(a) ≤ sup(b)) end """ @@ -95,9 +95,9 @@ Checks if the interval `a` is to the left of interval `b`. Implement the `precedes` function of the IEEE Std 1788-2015 (Table 10.3). """ -function precedes(a::F, b::F) where {F<:Interval} +function precedes(a::Interval, b::Interval) (isempty(a) || isempty(b)) && return true - return a.hi ≤ b.lo + return sup(a) ≤ inf(b) end """ @@ -110,24 +110,24 @@ Implement the `interior` function of the IEEE Std 1788-2015 (Table 9.3). """ function isinterior(a::Interval, b::Interval) isempty(a) && return true - return isweaklylessprime(b.lo, a.lo) && isweaklylessprime(a.hi, b.hi) + return isweaklylessprime(inf(b), inf(a)) && isweaklylessprime(sup(a), sup(b)) end """ isstrictless(a, b) Checks if the interval `a` is strictly less than interval `b`, which is true -if `a.lo < b.lo` and `a.hi < b.hi`. +if `inf(a) < inf(b)` and `sup(a) < sup(b)`. For variants in the definition of "strictly less than" for intervals see `strictprecedes` and `<`. Implement the `strictLess` function of the IEEE Std 1788-2015 (Table 10.3). """ -function isstrictless(a::F, b::F) where {F<:Interval} +function isstrictless(a::Interval, b::Interval) isempty(a) && isempty(b) && return true (isempty(a) || isempty(b)) && return false - return isweaklylessprime(a.lo, b.lo) && isweaklylessprime(a.hi, b.hi) + return isweaklylessprime(inf(a), inf(b)) && isweaklylessprime(sup(a), sup(b)) end """ @@ -137,9 +137,9 @@ Checks if the interval `a` is strictly to the left of interval `b`. Implement the `strictPrecedes` function of the IEEE Std 1788-2015 (Table 10.3). """ -function strictprecedes(a::F, b::F) where {F<:Interval} +function strictprecedes(a::Interval, b::Interval) (isempty(a) || isempty(b)) && return true - return a.hi < b.lo + return sup(a) < inf(b) end """ @@ -152,7 +152,7 @@ Implement the `disjoint` function of the IEEE Std 1788-2015 (Table 9.3). """ function isdisjoint(a::Interval, b::Interval) (isempty(a) || isempty(b)) && return true - return isweaklylessprime(b.hi, a.lo) || isweaklylessprime(a.hi, b.lo) + return isweaklylessprime(sup(b), inf(a)) || isweaklylessprime(sup(a), inf(b)) end function isdisjoint(a::Complex{F}, b::Complex{F}) where {F<:Interval} @@ -169,7 +169,7 @@ Implement the `isMember` function of the IEEE Std 1788-2015 (section 10.6.3). """ function in(x::Real, a::Interval) isinf(x) && return contains_infinity(a) - return a.lo <= x <= a.hi + return inf(a) <= x <= sup(a) end in(x::Interval, y::Interval) = throw(ArgumentError("$x ∈ $y is not defined, maybe you meant `⊂`")) @@ -180,7 +180,7 @@ contains_zero(x::Interval{T}) where T = zero(T) ∈ x isempty(x::Interval) = (inf(x) == Inf && sup(x) == -Inf) isentire(x::Interval) = (inf(x) == -Inf && sup(x) == Inf) -isbounded(x::Interval) = (isfinite(x.lo) && isfinite(x.hi)) || isempty(x) +isbounded(x::Interval) = (isfinite(inf(x)) && isfinite(sup(x))) || isempty(x) isunbounded(x::Interval) = !isbounded(x) """ @@ -191,7 +191,7 @@ representable float. Any float which is not exactly representable does *not* yield a thin interval. Corresponds to `isSingleton` of the standard. """ -isthin(x::Interval) = (x.lo == x.hi) +isthin(x::Interval) = (inf(x) == sup(x)) """ iscommon(x) @@ -211,18 +211,18 @@ Check whether an interval `x` is *atomic*, i.e. is unable to be split. This occurs when the interval is empty, or when the upper bound equals the lower bound or the bounds are consecutive floating point numbers. """ -isatomic(x::Interval) = isempty(x) || (x.lo == x.hi) || (x.hi == nextfloat(x.lo)) +isatomic(x::Interval) = isempty(x) || (inf(x) == sup(x)) || (sup(x) == nextfloat(inf(x))) """ isthinzero(x) Return whether the interval only contains zero. """ -isthinzero(x::Interval) = iszero(x.lo) && iszero(x.hi) +isthinzero(x::Interval) = iszero(inf(x)) && iszero(sup(x)) """ isthininteger(x) Return whether the inverval only contains a single integer. """ -isthininteger(x::Interval) = (x.lo == x.hi) && isinteger(x.lo) +isthininteger(x::Interval) = (inf(x) == sup(x)) && isinteger(inf(x)) diff --git a/src/intervals/interval_operations/cancellative.jl b/src/intervals/interval_operations/cancellative.jl index 559c1912c..8ba4954f9 100644 --- a/src/intervals/interval_operations/cancellative.jl +++ b/src/intervals/interval_operations/cancellative.jl @@ -19,7 +19,7 @@ function cancelminus(a::F, b::F) where {F<:Interval} diam(a) < diam(b) && return entireinterval(F) - c_lo, c_hi = bounds(@round(F, a.lo - b.lo, a.hi - b.hi)) + c_lo, c_hi = bounds(@round(F, inf(a) - inf(b), sup(a) - sup(b))) c_lo > c_hi && return entireinterval(F) # Corner case 2 (page 62), involving unbounded c @@ -30,8 +30,8 @@ function cancelminus(a::F, b::F) where {F<:Interval} isunbounded(c) && return c # Corner case 1 (page 62) involving finite precision for diam(a) and diam(b) - a_lo, a_hi = bounds(@round(F, b.lo + c_lo, b.hi + c_hi)) - (diam(a) == diam(b)) && (nextfloat(a.hi) < a_hi || prevfloat(a.lo) > a_lo) && return entireinterval(F) + a_lo, a_hi = bounds(@round(F, inf(b) + c_lo, sup(b) + c_hi)) + (diam(a) == diam(b)) && (nextfloat(sup(a)) < a_hi || prevfloat(inf(a)) > a_lo) && return entireinterval(F) return c end diff --git a/src/intervals/interval_operations/extended_div.jl b/src/intervals/interval_operations/extended_div.jl index 82e1c35f1..10999873a 100644 --- a/src/intervals/interval_operations/extended_div.jl +++ b/src/intervals/interval_operations/extended_div.jl @@ -16,7 +16,6 @@ function extended_div(a::F, b::F) where {T, F<:Interval{T}} blo, bhi = bounds(b) z = zero(T) if 0 < bhi && 0 > blo && 0 ∉ a - if ahi < 0 return (a / Interval(z, bhi), a / Interval(blo,z)) # return (F(T(-Inf), ahi / bhi), F(ahi / blo, T(Inf))) diff --git a/src/intervals/interval_operations/numeric.jl b/src/intervals/interval_operations/numeric.jl index fc004b4a6..0e5b8d278 100644 --- a/src/intervals/interval_operations/numeric.jl +++ b/src/intervals/interval_operations/numeric.jl @@ -37,7 +37,7 @@ sup(a::Real) = a Bounds of an interval as a tuple. """ -bounds(a::Interval) = (a.lo, a.hi) +bounds(a::Interval) = (a.lo, sup(a)) # Note that bounds does nothing with the sign of zero """ mid(a::Interval) @@ -50,19 +50,19 @@ function mid(a::F) where {T, F<:Interval{T}} isempty(a) && return convert(T, NaN) isentire(a) && return zero(T) - a.lo == -∞ && return nextfloat(a.lo) # IEEE-1788 section 12.12.8 - a.hi == +∞ && return prevfloat(a.hi) # IEEE-1788 section 12.12.8 + inf(a) == -∞ && return nextfloat(inf(a)) # IEEE-1788 section 12.12.8 + sup(a) == +∞ && return prevfloat(sup(a)) # IEEE-1788 section 12.12.8 - midpoint = (a.lo + a.hi) / 2 + midpoint = (inf(a) + sup(a)) / 2 isfinite(midpoint) && return _normalisezero(midpoint) - #= Fallback in case of overflow: a.hi + a.lo == +∞ or a.hi + a.lo == -∞. + #= Fallback in case of overflow: sup(a) + inf(a) == +∞ or sup(a) + inf(a) == -∞. This case can not be the default one as it does not pass several IEEE1788-2015 tests for small floats. =# - return _normalisezero(a.lo / 2 + a.hi / 2) + return _normalisezero(inf(a) / 2 + sup(a) / 2) end -mid(a::F) where {T, R<:Rational{T}, F<:Interval{R}} = (1//2) * (a.lo + a.hi) +mid(a::F) where {T, R<:Rational{T}, F<:Interval{R}} = (1//2) * (inf(a) + sup(a)) mid(a::Real) = a @@ -80,8 +80,8 @@ intervals. function scaled_mid(a::F, α) where {T, F<:Interval{T}} isempty(a) && return convert(T, NaN) - lo = (a.lo == -∞ ? nextfloat(a.lo) : a.lo) - hi = (a.hi == +∞ ? prevfloat(a.hi) : a.hi) + lo = (inf(a) == -∞ ? nextfloat(inf(a)) : inf(a)) + hi = (sup(a) == +∞ ? prevfloat(sup(a)) : sup(a)) β = convert(T, α) @@ -103,7 +103,7 @@ Implement the `wid` function of the IEEE Std 1788-2015 (Table 9.2). """ function diam(a::F) where {T, F<:Interval{T}} isempty(a) && return convert(T, NaN) - return -(a.hi, a.lo, RoundUp) # IEEE1788 section 12.12.8 + return -(sup(a), inf(a), RoundUp) # IEEE1788 section 12.12.8 end diam(a::Real) = zero(a) @@ -134,7 +134,7 @@ flavor. function midpoint_radius(a::F) where {T, F<:Interval{T}} isempty(a) && return convert(T, NaN), convert(T, NaN) m = mid(a) - return m, max(m - a.lo, a.hi - m) + return m, max(m - inf(a), sup(a) - m) end @@ -147,7 +147,7 @@ Implement the `mag` function of the IEEE Std 1788-2015 (Table 9.2). """ function mag(a::F) where {T, F<:Interval{T}} isempty(a) && return convert(T, NaN) - return max( abs(a.lo), abs(a.hi) ) + return max( abs(inf(a)), abs(sup(a)) ) end """ @@ -160,5 +160,5 @@ Implement the `mig` function of the IEEE Std 1788-2015 (Table 9.2). function mig(a::F) where {T, F<:Interval{T}} isempty(a) && return convert(T, NaN) contains_zero(a) && return zero(T) - return min( abs(a.lo), abs(a.hi) ) + return min( abs(inf(a)), abs(sup(a)) ) end diff --git a/src/intervals/interval_operations/overlap.jl b/src/intervals/interval_operations/overlap.jl index 247f5a2a2..70f24db90 100644 --- a/src/intervals/interval_operations/overlap.jl +++ b/src/intervals/interval_operations/overlap.jl @@ -44,8 +44,8 @@ function overlap(a::Interval, b::Interval) isempty(b) && return Overlap.second_empty # States with both intervals nonempty - strictprecedes(a, b) && return Overlap.before - !isthin(a) && !isthin(b) && sup(a) == inf(b) && return Overlap.meets + sup(a) < inf(b) && return Overlap.before + inf(a) != sup(a) && inf(b) != sup(b) && sup(a) == inf(b) && return Overlap.meets inf(a) < inf(b) && sup(a) < sup(b) && sup(a) > inf(b) && return Overlap.overlaps inf(a) == inf(b) && sup(a) < sup(b) && return Overlap.starts inf(b) < inf(a) && sup(a) < sup(b) && return Overlap.contained_by @@ -55,6 +55,6 @@ function overlap(a::Interval, b::Interval) inf(b) > inf(a) && sup(a) > sup(b) && return Overlap.contains inf(a) == inf(b) && sup(a) > sup(b) && return Overlap.started_by inf(a) > inf(b) && sup(a) > sup(b) && inf(a) < sup(b) && return Overlap.overlapped_by - !isthin(a) && !isthin(b) && inf(a) == sup(b) && return Overlap.met_by - strictprecedes(b, a) && return Overlap.after + inf(a) != sup(a) && inf(b) != sup(b) && inf(a) == sup(b) && return Overlap.met_by + sup(b) < sup(a) && return Overlap.after end diff --git a/src/intervals/interval_operations/pointwise_boolean.jl b/src/intervals/interval_operations/pointwise_boolean.jl index 0454b5bc2..269a79825 100644 --- a/src/intervals/interval_operations/pointwise_boolean.jl +++ b/src/intervals/interval_operations/pointwise_boolean.jl @@ -74,7 +74,7 @@ const pointwise_bool_functions = ( ## :ieee1788 # See Table 10.3 -==(::PointwisePolitic{:ieee1788}, x::Interval, y::Interval) = x.lo == y.lo && x.hi == y.hi +==(::PointwisePolitic{:ieee1788}, x::Interval, y::Interval) = inf(x) == inf(y) && sup(x) == sup(y) <(::PointwisePolitic{:ieee1788}, x::Interval, y::Interval) = isstrictless(x, y) @@ -91,13 +91,13 @@ isinf(::PointwisePolitic{:ieee1788}, x::Interval) = contains_infinity(x) && isth isfinite(::PointwisePolitic{:ieee1788}, x::Interval) = !isinf(PointwisePolitic{:ieee1788}(), x) iszero(::PointwisePolitic{:ieee1788}, x::Interval) = isthinzero(x) -isinteger(::PointwisePolitic{:ieee1788}, x::Interval) = (x.lo == x.hi) && isinteger(x.lo) +isinteger(::PointwisePolitic{:ieee1788}, x::Interval) = (inf(x) == sup(x)) && isinteger(inf(x)) ## :ternary function ==(::PointwisePolitic{:ternary}, x::Interval, y::Interval) - isthin(x) && isthin(y) && x.lo == y.lo && return true - (x.hi < y.lo || x.lo > y.hi) && return false + isthin(x) && isthin(y) && inf(x) == inf(y) && return true + (sup(x) < inf(y) || inf(x) > sup(y)) && return false return missing end @@ -132,8 +132,8 @@ isfinite(::PointwisePolitic{:ternary}, x::Interval) = !isinf(PointwisePolitic{:t iszero(::PointwisePolitic{:ternary}, x::Interval) = ==(PointwisePolitic{:ternary}(), x, 0) function isinteger(::PointwisePolitic{:ternary}, x::Interval) - (x.lo == x.hi) && isinteger(x.lo) && return true - floor(x.hi) < ceil(x.lo) && return false + (inf(x) == sup(x)) && isinteger(inf(x)) && return true + floor(sup(x)) < ceil(inf(x)) && return false return missing end diff --git a/src/intervals/interval_operations/set_operations.jl b/src/intervals/interval_operations/set_operations.jl index d1d2f023b..5a562a16f 100644 --- a/src/intervals/interval_operations/set_operations.jl +++ b/src/intervals/interval_operations/set_operations.jl @@ -17,7 +17,7 @@ Implement the `intersection` function of the IEEE Std 1788-2015 (section 9.3). """ function intersect(a::Interval{T}, b::Interval{S}) where {T, S} isdisjoint(a, b) && return emptyinterval(promote_type(T, S)) - return Interval{promote_type(T, S)}(max(a.lo, b.lo), min(a.hi, b.hi)) + return Interval{promote_type(T, S)}(max(inf(a), inf(b)), min(sup(a), sup(b))) end function intersect(a::Complex{F}, b::Complex{F}) where {F<:Interval} @@ -52,9 +52,9 @@ all of `a` and `b`. Implement the `converxHull` function of the IEEE Std 1788-2015 (section 9.3). """ -hull(a::F, b::F) where {F<:Interval} = F(min(a.lo, b.lo), max(a.hi, b.hi)) +hull(a::F, b::F) where {F<:Interval} = F(min(inf(a), inf(b)), max(sup(a), sup(b))) hull(a::F, b::G) where {F<:Interval, G<:Interval} = - promote_type(F, G)(min(a.lo, b.lo), max(a.hi, b.hi)) + promote_type(F, G)(min(inf(a), inf(b)), max(sup(a), sup(b))) hull(a::Complex{F},b::Complex{F}) where {F<:Interval} = complex(hull(real(a), real(b)), hull(imag(a), imag(b))) hull(a...) = reduce(hull, a) @@ -91,9 +91,9 @@ function setdiff(x::F, y::F) where {F<:Interval} isempty(intersection) && return [x] intersection ≛ x && return F[] # x is subset of y; setdiff is empty - x.lo == intersection.lo && return [F(intersection.hi, x.hi)] - x.hi == intersection.hi && return [F(x.lo, intersection.lo)] + inf(x) == inf(intersection) && return [F(sup(intersection), sup(x))] + sup(x) == sup(intersection) && return [F(inf(x), inf(intersection))] - return [F(x.lo, y.lo), F(y.hi, x.hi)] + return [F(inf(x), inf(y)), F(sup(y), sup(x))] end diff --git a/src/intervals/real_interface.jl b/src/intervals/real_interface.jl index f496efc19..8d10733af 100644 --- a/src/intervals/real_interface.jl +++ b/src/intervals/real_interface.jl @@ -32,7 +32,7 @@ Float64 """ numtype(::Interval{T}) where T = T -eps(a::F) where {F<:Interval} = F(max(eps(a.lo), eps(a.hi))) +eps(a::F) where {F<:Interval} = F(max(eps(inf(a)), eps(sup(a)))) eps(::Type{F}) where {T, F<:Interval{T}} = F(eps(T)) """ @@ -46,8 +46,8 @@ Note that in `IntervalArithmetic.jl`, equality of intervals is given by The latter is reserved for the pointwise extension of equality to intervals and uses three-way logic by default. """ -hash(x::Interval, h::UInt) = hash(x.hi, hash(x.lo, hash(Interval, h))) +hash(x::Interval, h::UInt) = hash(sup(x), hash(inf(x), hash(Interval, h))) # TODO No idea where this comes from and if it is the correct place to put it. -dist(a::Interval, b::Interval) = max(abs(a.lo-b.lo), abs(a.hi-b.hi)) +dist(a::Interval, b::Interval) = max(abs(inf(a)-inf(b)), abs(sup(a)-sup(b))) diff --git a/src/multidim/setdiff.jl b/src/multidim/setdiff.jl index a45fee94f..a2b6ce5f4 100644 --- a/src/multidim/setdiff.jl +++ b/src/multidim/setdiff.jl @@ -11,10 +11,13 @@ function _setdiff(x::Interval{T}, y::Interval{T}) where T isempty(intersection) && return (x, emptyinterval(T)) intersection ≛ x && return (emptyinterval(T), emptyinterval(T)) # x is subset of y; setdiff is empty - x.lo == intersection.lo && return (Interval(intersection.hi, x.hi), emptyinterval(T)) - x.hi == intersection.hi && return (Interval(x.lo, intersection.lo), emptyinterval(T)) + xlo, xhi = bounds(x) + ylo, yhi = bounds(y) + intersectionlo, intersectionhi = bounds(intersection) + xlo == intersectionlo && return (Interval(intersectionhi, xhi), emptyinterval(T)) + xhi == intersectionhi && return (Interval(xlo, intersectionlo), emptyinterval(T)) - return (Interval(x.lo, y.lo), Interval(y.hi, x.hi)) + return (Interval(xlo, ylo), Interval(yhi, xhi)) end diff --git a/src/plot_recipes/plot_recipes.jl b/src/plot_recipes/plot_recipes.jl index 173b04aff..e708c6997 100644 --- a/src/plot_recipes/plot_recipes.jl +++ b/src/plot_recipes/plot_recipes.jl @@ -8,10 +8,12 @@ using RecipesBase seriesalpha --> 0.5 seriestype := :shape - x = [x.lo, x.hi, x.hi, x.lo] - y = [y.lo, y.lo, y.hi, y.hi] + xlo, xhi = bounds(x) + ylo, yhi = bounds(y) + xv = [xlo, xhi, xhi, xlo] + yv = [ylo, ylo, yhi, yhi] - x, y + xv, yv end # Plot a vector of 2D IntervalBoxes: @@ -26,9 +28,11 @@ end for xx in v (x, y) = xx + xlo, xhi = bounds(x) + ylo, yhi = bounds(y) # use NaNs to separate - append!(xs, [x.lo, x.hi, x.hi, x.lo, NaN]) - append!(ys, [y.lo, y.lo, y.hi, y.hi, NaN]) + append!(xs, [xlo, xhi, xhi, xlo, NaN]) + append!(ys, [ylo, ylo, yhi, yhi, NaN]) end diff --git a/src/rand.jl b/src/rand.jl index 86c29b7e2..e5e27ed33 100644 --- a/src/rand.jl +++ b/src/rand.jl @@ -1,6 +1,6 @@ using Random -Base.rand(X::Interval{T}) where {T} = X.lo + rand(T) * (X.hi - X.lo) +Base.rand(X::Interval{T}) where {T} = inf(X) + rand(T) * (sup(X) - inf(X)) Base.rand(X::IntervalBox) = rand.(X)