Skip to content

Commit 3e2e99e

Browse files
authored
Merge pull request #559 from OlivierHnt/1.0-bounds-type
1.0-dev: Enforce the bounds of `Interval` to be a `Rational` or an `AbstractFloat`
2 parents 4d6bd15 + 44764fa commit 3e2e99e

File tree

21 files changed

+182
-185
lines changed

21 files changed

+182
-185
lines changed

src/bisect.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
const where_bisect = 0.49609375
32

43
"""
@@ -59,7 +58,7 @@ Splits `x` in `n` intervals in each dimension of the same diameter. These
5958
intervals are combined in all possible `IntervalBox`-es, which are returned
6059
as a vector.
6160
"""
62-
@generated function mince(x::IntervalBox{N,T}, n) where {N,T}
61+
@generated function mince(x::IntervalBox{N,T}, n) where {N,T<:NumTypes}
6362
quote
6463
nodes_matrix = Array{Interval{T},2}(undef, n, N)
6564
for i in 1:N

src/decorations/intervals.jl

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,17 @@ a flag that records the status of the interval when thought of as the result
2626
of a previously executed sequence of functions acting on an initial interval.
2727
"""
2828

29-
struct DecoratedInterval{T}
29+
struct DecoratedInterval{T<:NumTypes}
3030
interval::Interval{T}
3131
decoration::DECORATION
3232
end
3333

3434
DecoratedInterval(I::DecoratedInterval, dec::DECORATION) = DecoratedInterval(I.interval, dec)
3535

3636
function DecoratedInterval(a::T, b::S, d::DECORATION) where {T<:Real, S<:Real}
37-
BoundsType = promote_numtype(T, S)
38-
is_valid_interval(a, b) || return DecoratedInterval(Interval{BoundsType}(a, b), ill)
39-
return DecoratedInterval(Interval{BoundsType}(a, b), d)
37+
NumType = promote_numtype(T, S)
38+
is_valid_interval(a, b) || return DecoratedInterval(Interval{NumType}(a, b), ill)
39+
return DecoratedInterval(Interval{NumType}(a, b), d)
4040
end
4141

4242
DecoratedInterval(a::Real, d::DECORATION) = DecoratedInterval(a, a, d)
@@ -49,12 +49,12 @@ function DecoratedInterval{T}(I::Interval) where {T}
4949
return DecoratedInterval{T}(I, d)
5050
end
5151

52-
DecoratedInterval(I::Interval) = DecoratedInterval{default_bound()}(I)
52+
DecoratedInterval(I::Interval{T}) where {T<:NumTypes} = DecoratedInterval{T}(I)
5353

5454
function DecoratedInterval(a::T, b::S) where {T<:Real, S<:Real}
55-
BoundsType = promote_numtype(T, S)
56-
is_valid_interval(a, b) || return DecoratedInterval(Interval{BoundsType}(a, b), ill)
57-
return DecoratedInterval(Interval{BoundsType}(a, b))
55+
NumType = promote_numtype(T, S)
56+
is_valid_interval(a, b) || return DecoratedInterval(Interval{NumType}(a, b), ill)
57+
return DecoratedInterval(Interval{NumType}(a, b))
5858
end
5959

6060
DecoratedInterval(a::Real) = DecoratedInterval(a, a)

src/display.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ end
212212

213213
# `String` representation of an `Interval`
214214

215-
function basic_representation(a::Interval{T}, format::Symbol) where {T}
215+
function basic_representation(a::Interval{T}, format::Symbol) where {T<:AbstractFloat}
216216
isempty(a) && return ""
217217
sigdigits = display_params.sigdigits
218218
if format === :full

src/intervals/arithmetic/basic.jl

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@
1515
1616
Implement the `add` function of the IEEE Std 1788-2015 (Table 9.1).
1717
"""
18-
function +(a::F, b::T) where {T, F<:Interval{T}}
18+
function +(a::F, b::T) where {T<:NumTypes,F<:Interval{T}}
1919
isempty(a) && return emptyinterval(F)
2020
return @round(F, inf(a) + b, sup(a) + b)
2121
end
22-
+(a::Interval{T}, b::Real) where {T} = a + interval(T, b)
23-
+(a::Real, b::Interval{T}) where {T} = b + a
22+
+(a::Interval{T}, b::Real) where {T<:NumTypes} = a + interval(T, b)
23+
+(a::Real, b::Interval{T}) where {T<:NumTypes} = b + a
2424

2525
function +(a::F, b::F) where {F<:Interval}
2626
(isempty(a) || isempty(b)) && return emptyinterval(F)
@@ -42,16 +42,16 @@ Implement the `neg` function of the IEEE Std 1788-2015 (Table 9.1).
4242
4343
Implement the `sub` function of the IEEE Std 1788-2015 (Table 9.1).
4444
"""
45-
function -(a::F, b::T) where {T<:Real, F<:Interval{T}}
45+
function -(a::F, b::T) where {T<:NumTypes,F<:Interval{T}}
4646
isempty(a) && return emptyinterval(F)
4747
return @round(F, inf(a) - b, sup(a) - b)
4848
end
49-
function -(b::T, a::F) where {T, F<:Interval{T}}
49+
function -(b::T, a::F) where {T<:NumTypes,F<:Interval{T}}
5050
isempty(a) && return emptyinterval(F)
5151
return @round(F, b - sup(a), b - inf(a))
5252
end
53-
-(a::Interval{T}, b::Real) where {T} = a - interval(T, b)
54-
-(a::Real, b::Interval{T}) where {T} = interval(T, a) - b
53+
-(a::Interval{T}, b::Real) where {T<:NumTypes} = a - interval(T, b)
54+
-(a::Real, b::Interval{T}) where {T<:NumTypes} = interval(T, a) - b
5555

5656
function -(a::F, b::F) where {F<:Interval}
5757
(isempty(a) || isempty(b)) && return emptyinterval(F)
@@ -77,7 +77,7 @@ Implement the `mul` function of the IEEE Std 1788-2015 (Table 9.1).
7777
7878
Note: the behavior of the multiplication is flavor dependent for some edge cases.
7979
"""
80-
function *(a::F, b::T) where {T<:Real, F<:Interval{T}}
80+
function *(a::F, b::T) where {T<:NumTypes,F<:Interval{T}}
8181
isempty(a) && return emptyinterval(F)
8282
(isthinzero(a) || iszero(b)) && return zero(F)
8383

@@ -87,8 +87,8 @@ function *(a::F, b::T) where {T<:Real, F<:Interval{T}}
8787
return @round(F, sup(a)*b, inf(a)*b)
8888
end
8989
end
90-
*(a::Interval{T}, b::Real) where {T} = a * interval(T, b)
91-
*(a::Real, b::Interval{T}) where {T} = b * a
90+
*(a::Interval{T}, b::Real) where {T<:NumTypes} = a * interval(T, b)
91+
*(a::Real, b::Interval{T}) where {T<:NumTypes} = b * a
9292

9393
function *(a::F, b::F) where {F<:Interval}
9494
(isempty(a) || isempty(b)) && return emptyinterval(F)
@@ -99,13 +99,13 @@ end
9999
*(a::Interval, b::Interval) = *(promote(a, b)...)
100100

101101
# Helper functions for multiplication
102-
function unbounded_mult(::Type{F}, x::T, y::T, r::RoundingMode) where {T, F<:Interval{T}}
102+
function unbounded_mult(::Type{F}, x::T, y::T, r::RoundingMode) where {T<:NumTypes,F<:Interval{T}}
103103
iszero(x) && return sign(y) * zero_times_infinity(T)
104104
iszero(y) && return sign(x) * zero_times_infinity(T)
105105
return *(x, y, r)
106106
end
107107

108-
function mult(op, a::F, b::F) where {T, F<:Interval{T}}
108+
function mult(op, a::F, b::F) where {T<:NumTypes,F<:Interval{T}}
109109
if inf(b) >= zero(T)
110110
inf(a) >= zero(T) && return @round(F, op(inf(a), inf(b)), op(sup(a), sup(b)))
111111
sup(a) <= zero(T) && return @round(F, op(inf(a), sup(b)), op(sup(a), inf(b)))
@@ -131,7 +131,7 @@ Implement the `div` function of the IEEE Std 1788-2015 (Table 9.1).
131131
132132
Note: the behavior of the division is flavor dependent for some edge cases.
133133
"""
134-
function /(a::F, b::Real) where {F<:Interval}
134+
function /(a::F, b::T) where {T<:NumTypes,F<:Interval{T}}
135135
isempty(a) && return emptyinterval(T)
136136
iszero(b) && return div_by_thin_zero(a)
137137

@@ -142,9 +142,11 @@ function /(a::F, b::Real) where {F<:Interval}
142142
end
143143
end
144144

145+
/(a::Interval{T}, b::Real) where {T<:NumTypes} = a / interval(T, b)
146+
145147
/(a::Real, b::Interval) = a * inv(b)
146148

147-
function /(a::F, b::F) where {T, F<:Interval{T}}
149+
function /(a::F, b::F) where {T<:NumTypes,F<:Interval{T}}
148150
(isempty(a) || isempty(b)) && return emptyinterval(F)
149151
isthinzero(b) && return div_by_thin_zero(a)
150152

@@ -162,13 +164,13 @@ function /(a::F, b::F) where {T, F<:Interval{T}}
162164
isthinzero(a) && return a
163165

164166
if iszero(inf(b))
165-
inf(a) >= zero(T) && return @round(F, inf(a)/sup(b), T(Inf))
166-
sup(a) <= zero(T) && return @round(F, T(-Inf), sup(a)/sup(b))
167+
inf(a) >= zero(T) && return @round(F, inf(a)/sup(b), typemax(T))
168+
sup(a) <= zero(T) && return @round(F, typemin(T), sup(a)/sup(b))
167169
return entireinterval(F)
168170

169171
elseif iszero(sup(b))
170-
inf(a) >= zero(T) && return @round(F, T(-Inf), inf(a)/inf(b))
171-
sup(a) <= zero(T) && return @round(F, sup(a)/inf(b), T(Inf))
172+
inf(a) >= zero(T) && return @round(F, typemin(T), inf(a)/inf(b))
173+
sup(a) <= zero(T) && return @round(F, sup(a)/inf(b), typemax(T))
172174
return entireinterval(F)
173175

174176
else
@@ -186,12 +188,12 @@ Implement the `recip` function of the IEEE Std 1788-2015 (Table 9.1).
186188
187189
Note: the behavior of this function is flavor dependent for some edge cases.
188190
"""
189-
function inv(a::F) where {T, F<:Interval{T}}
191+
function inv(a::F) where {T<:NumTypes,F<:Interval{T}}
190192
isempty(a) && return emptyinterval(F)
191193

192194
if zero(T) a
193-
inf(a) < zero(T) == sup(a) && return @round(F, T(-Inf), inv(inf(a)))
194-
inf(a) == zero(T) < sup(a) && return @round(F, inv(sup(a)), T(Inf))
195+
inf(a) < zero(T) == sup(a) && return @round(F, typemin(T), inv(inf(a)))
196+
inf(a) == zero(T) < sup(a) && return @round(F, inv(sup(a)), typemax(T))
195197
inf(a) < zero(T) < sup(a) && return entireinterval(F)
196198
isthinzero(a) && return div_by_thin_zero(one(F))
197199
end
@@ -217,7 +219,7 @@ Fused multiply-add.
217219
218220
Implement the `fma` function of the IEEE Std 1788-2015 (Table 9.1).
219221
"""
220-
function fma(a::F, b::F, c::F) where {T, F<:Interval{T}}
222+
function fma(a::F, b::F, c::F) where {T<:NumTypes,F<:Interval{T}}
221223
(isempty(a) || isempty(b) || isempty(c)) && return emptyinterval(F)
222224

223225
if isentire(a)

src/intervals/arithmetic/power.jl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ end
1919
# overwrite new behaviour for small integer powers from
2020
# https://github.com/JuliaLang/julia/pull/24240:
2121

22-
Base.literal_pow(::typeof(^), x::Interval{T}, ::Val{p}) where {T,p} = x^p
22+
Base.literal_pow(::typeof(^), x::Interval{T}, ::Val{p}) where {T<:NumTypes,p} = x^p
2323

2424
# CRlibm does not contain a correctly-rounded ^ function for Float64
2525
# Use the BigFloat version from MPFR instead, which is correctly-rounded.
@@ -118,13 +118,13 @@ function ^(a::F, x::BigFloat) where {F<:Interval{BigFloat}}
118118
return hull(lo, hi)
119119
end
120120

121-
function ^(a::Interval{Rational{T}}, x::AbstractFloat) where {T<:Integer}
122-
a = Interval{Float64}(inf(a).num/inf(a).den, sup(a).num/sup(a).den)
121+
function ^(a::F, x::AbstractFloat) where {F<:Interval{<:Rational}}
122+
a = float(F)(inf(a).num/inf(a).den, sup(a).num/sup(a).den)
123123
return F(a^x)
124124
end
125125

126126
# Rational power
127-
function ^(a::F, x::Rational{R}) where {F<:Interval, R<:Integer}
127+
function ^(a::F, x::Rational{R}) where {F<:Interval,R<:Integer}
128128
p = x.num
129129
q = x.den
130130

@@ -244,7 +244,7 @@ for f in (:exp2, :exp10, :cbrt)
244244
end
245245

246246
for f in (:log, :log2, :log10)
247-
@eval function ($f)(a::F) where {T, F<:Interval{T}}
247+
@eval function ($f)(a::F) where {T<:NumTypes,F<:Interval{T}}
248248
domain = F(0, Inf)
249249
a = a domain
250250

@@ -254,7 +254,7 @@ for f in (:log, :log2, :log10)
254254
end
255255
end
256256

257-
function log1p(a::F) where {T, F<:Interval{T}}
257+
function log1p(a::F) where {T<:NumTypes,F<:Interval{T}}
258258
domain = F(-1, Inf)
259259
a = a domain
260260

@@ -290,7 +290,7 @@ function nthroot(a::F, n::Integer) where {F<:Interval{BigFloat}}
290290
return interval(low , high)
291291
end
292292

293-
function nthroot(a::F, n::Integer) where {T, F<:Interval{T}}
293+
function nthroot(a::F, n::Integer) where {T<:NumTypes,F<:Interval{T}}
294294
n == 1 && return a
295295
n == 2 && return sqrt(a)
296296

src/intervals/arithmetic/trigonometric.jl

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77

88
const halfpi = pi / 2.0
99

10-
half_pi(::Type{Interval{T}}) where {T} = scale(0.5, interval(T, π))
11-
two_pi(::Type{Interval{T}}) where {T} = scale(2, interval(T, π))
10+
half_pi(::Type{Interval{T}}) where {T<:NumTypes} = scale(0.5, interval(T, π))
11+
two_pi(::Type{Interval{T}}) where {T<:NumTypes} = scale(2, interval(T, π))
1212

13-
function range_atan(::Type{F}) where {T, F<:Interval{T}}
13+
function range_atan(::Type{F}) where {T,F<:Interval{T}}
1414
temp = sup(interval(T, π)) # Using F(-π, π) converts -π to Float64 before Interval construction
1515
return F(-temp, temp)
1616
end
@@ -50,7 +50,7 @@ end
5050
5151
Implement the `sin` function of the IEEE Std 1788-2015 (Table 9.1).
5252
"""
53-
function sin(a::F) where {T, F<:Interval{T}}
53+
function sin(a::F) where {T<:NumTypes,F<:Interval{T}}
5454
isempty(a) && return a
5555

5656
whole_range = F(-1, 1)
@@ -135,7 +135,7 @@ function sin(a::F) where {F<:Interval{Float64}}
135135
end
136136
end
137137

138-
function sinpi(a::Interval{T}) where {T}
138+
function sinpi(a::Interval{T}) where {T<:NumTypes}
139139
isempty(a) && return a
140140
w = a * interval(T, π)
141141
return sin(w)
@@ -146,7 +146,7 @@ end
146146
147147
Implement the `cos` function of the IEEE Std 1788-2015 (Table 9.1).
148148
"""
149-
function cos(a::F) where {T, F<:Interval{T}}
149+
function cos(a::F) where {T<:NumTypes,F<:Interval{T}}
150150
isempty(a) && return a
151151

152152
whole_range = F(-1, 1)
@@ -229,7 +229,7 @@ function cos(a::F) where {F<:Interval{Float64}}
229229
end
230230
end
231231

232-
function cospi(a::Interval{T}) where T
232+
function cospi(a::Interval{T}) where {T<:NumTypes}
233233
isempty(a) && return a
234234
w = a * interval(T, π)
235235
return cos(w)
@@ -240,7 +240,7 @@ end
240240
241241
Implement the `tan` function of the IEEE Std 1788-2015 (Table 9.1).
242242
"""
243-
function tan(a::F) where {T, F<:Interval{T}}
243+
function tan(a::F) where {T<:NumTypes,F<:Interval{T}}
244244
isempty(a) && return a
245245

246246
diam(a) > inf(interval(T, π)) && return entireinterval(a)
@@ -295,7 +295,7 @@ end
295295
296296
Implement the `cot` function of the IEEE Std 1788-2015 (Table 9.1).
297297
"""
298-
function cot(a::F) where {T, F<:Interval{T}}
298+
function cot(a::F) where {T<:NumTypes,F<:Interval{T}}
299299
isempty(a) && return a
300300

301301
diam(a) > inf(interval(T, π)) && return entireinterval(a)
@@ -340,7 +340,7 @@ cot(a::F) where {F<:Interval{Float64}} = atomic(F, cot(big(a)))
340340
341341
Implement the `sec` function of the IEEE Std 1788-2015 (Table 9.1).
342342
"""
343-
function sec(a::F) where {T, F<:Interval{T}}
343+
function sec(a::F) where {T<:NumTypes,F<:Interval{T}}
344344
isempty(a) && return a
345345

346346
diam(a) > inf(interval(T, π)) && return entireinterval(a)
@@ -379,7 +379,7 @@ sec(a::F) where {F<:Interval{Float64}} = atomic(F, sec(big(a)))
379379
380380
Implement the `csc` function of the IEEE Std 1788-2015 (Table 9.1).
381381
"""
382-
function csc(a::F) where {T, F<:Interval{T}}
382+
function csc(a::F) where {T<:NumTypes,F<:Interval{T}}
383383
isempty(a) && return a
384384

385385
diam(a) > inf(interval(T, π)) && return entireinterval(a)
@@ -466,7 +466,7 @@ function atan(a::F) where {F<:Interval}
466466
return @round(F, atan(alo), atan(ahi))
467467
end
468468

469-
function atan(y::Interval{T}, x::Interval{S}) where {T, S}
469+
function atan(y::Interval{T}, x::Interval{S}) where {T<:NumTypes,S<:NumTypes}
470470
F = Interval{promote_type(T, S)}
471471
(isempty(y) || isempty(x)) && return emptyinterval(F)
472472
return F(atan(big(y), big(x)))

0 commit comments

Comments
 (0)