Manipulating intervals
Display modes
There are several useful output representations for intervals. The display is controlled globally by the setdisplay
function, which has the following options:
interval output format:
:infsup
: output of the form[1.09999, 1.30001]
, rounded to the current number of significant figures.:full
: output of the formInterval(1.0999999999999999, 1.3)
, as in theshowfull
function.:midpoint
: output in the midpoint-radius form, e.g.1.2 ± 0.100001
.
sigdigits :: Int
keyword argument: number of significant digits to show in standard mode.decorations :: Bool
keyword argument: whether to show decorations or not.
julia> using IntervalArithmetic
julia> a = interval(1.1, pi) # default display
Interval{Float64}(1.1, 3.1415926535897936, com, true)
julia> setdisplay(; sigdigits = 10)
Display options: - format: full - decorations: true (ignored) - NG flag: true (ignored) - significant digits: 10 (ignored)
julia> a
Interval{Float64}(1.1, 3.1415926535897936, com, true)
julia> setdisplay(:full)
Display options: - format: full - decorations: true (ignored) - NG flag: true (ignored) - significant digits: 10 (ignored)
julia> a
Interval{Float64}(1.1, 3.1415926535897936, com, true)
julia> setdisplay(:midpoint)
Display options: - format: midpoint - decorations: true - NG flag: true - significant digits: 10
julia> a
(2.120796327 ± 1.020796327)_com
julia> setdisplay(; sigdigits = 4)
Display options: - format: midpoint - decorations: true - NG flag: true - significant digits: 4
julia> a
(2.121 ± 1.021)_com
julia> setdisplay(:infsup)
Display options: - format: infsup - decorations: true - NG flag: true - significant digits: 4
julia> a
[1.1, 3.142]_com
Arithmetic operations
Basic arithmetic operations (+
, -
, *
, /
, ^
) are defined for pairs of intervals in a standard way: the result is the smallest interval containing the result of operating with each element of each interval. More precisely, for two intervals $X$ and $Y$ and an operation $\bigcirc$, we define the operation on the two intervals by
\[X \bigcirc Y \bydef \{ x \bigcirc y \,:\, x \in X \text{ and } y \in Y \}.\]
For example,
julia> using IntervalArithmetic
julia> setdisplay(:full)
Display options: - format: full - decorations: true (ignored) - NG flag: true (ignored) - significant digits: 4 (ignored)
julia> X = interval(0, 1)
Interval{Float64}(0.0, 1.0, com, true)
julia> Y = interval(1, 2)
Interval{Float64}(1.0, 2.0, com, true)
julia> X + Y
Interval{Float64}(1.0, 3.0, com, true)
Due to the above definition, subtraction of two intervals may give poor enclosures:
julia> X - X
Interval{Float64}(-1.0, 1.0, com, true)
Elementary functions
The main elementary functions are implemented. The functions for Interval{Float64}
internally use routines from the correctly-rounded CRlibm library where possible, i.e. for the following functions defined in that library:
exp
,expm1
log
,log1p
,log2
,log10
sin
,cos
,tan
asin
,acos
,atan
sinh
,cosh
Other functions that are implemented for Interval{Float64}
internally convert to an Interval{BigFloat}
, and then use routines from the MPFR library (BigFloat
in Julia):
^
exp2
,exp10
atan
,atanh
In particular, in order to obtain correct rounding for the power function (^
), intervals are converted to and from BigFloat
; this implies a significant slow-down in this case.
For example,
julia> X = interval(1)
Interval{Float64}(1.0, 1.0, com, true)
julia> sin(X)
Interval{Float64}(0.8414709848078965, 0.8414709848078966, com, true)
julia> cos(cosh(X))
Interval{Float64}(0.027712143770207736, 0.02771214377020796, com, true)
julia> setprecision(BigFloat, 53)
53
julia> Y = big(X)
Interval{BigFloat}(1.0, 1.0, com, true)
julia> sin(Y)
Interval{BigFloat}(0.8414709848078965, 0.84147098480789662, com, true)
julia> cos(cosh(Y))
Interval{BigFloat}(0.027712143770207736, 0.027712143770207961, com, true)
julia> setprecision(BigFloat, 128)
128
julia> sin(Y)
Interval{BigFloat}(0.8414709848078965, 0.84147098480789662, com, true)
Comparisons
If the result of a comparison can be established with guarantee, it will be return, otherwise, an error is thrown.
julia> interval(1) < interval(2)
true
julia> interval(1, 5) < interval(7, 9)
true
julia> interval(1, 5) < interval(4.99, 9)
ERROR: ArgumentError: `<` is purposely not supported for overlapping intervals. See instead `strictprecedes`
julia> interval(1.23) == interval(1.23)
true
julia> interval(1.23) == interval(4.99, 9)
false
julia> interval(1.23) == interval(1.2, 1.3)
ERROR: ArgumentError: `==` is purposely not supported for overlapping non-thin intervals. See instead `isequal_interval`
In particular, if ... else ... end
statements used for floating-points will often break with intervals.
See Philosophy for more details and why this choice was made.
Set operations
Set operations are all disallowed and error on intervals to avoid ambiguities. To perform set operations on intervals, use the *_interval
equivalent explicitly, e.g. issubset_interval
instead of issubset
.
julia> issubset(interval(1, 2), interval(2))
ERROR: ArgumentError: `issubset` is purposely not supported for intervals. See instead `issubset_interval`
julia> issubset_interval(interval(1, 2), interval(2))
false
julia> intersect(interval(1, 2), interval(2))
ERROR: ArgumentError: `intersect` is purposely not supported for intervals. See instead `intersect_interval`
julia> intersect_interval(interval(1, 2), interval(2))
Interval{Float64}(2.0, 2.0, trv, true)
See Philosophy for more details and why this choice was made.
Piecewise functions
Since intervals don't play well with if ... else ... end
statement, we provide a utility to define function by pieces:
julia> myabs = Piecewise( Domain{:open, :closed}(-Inf, 0) => x -> -x, Domain{:open, :open}(0, Inf) => identity )
Piecewise function with 2 pieces: (-Inf, 0] -> Main.var"#1#2"() (0, Inf) -> identity
julia> myabs(-1.23)
1.23
julia> myabs(interval(-1, 23))
Interval{Float64}(0.0, 23.0, def, true)
The resulting function work with both standard numbers and intervals, and deal properly with the decorations of intervals.
Custom interval bounds type
A BareInterval{T}
or Interval{T}
have the restriction T <: Union{Rational,AbstractFloat}
which is the parametric type for the bounds of the interval. Supposing one wishes to use their own numeric type MyNumType <: Union{Rational,AbstractFloat}
, they must provide their own arithmetic operations (with correct rounding!).