|
5 | 5 | # helper functions
|
6 | 6 |
|
7 | 7 | function _quadrant(x::AbstractFloat)
|
| 8 | + # NOTE: this algorithm may be flawed as it relies on `rem2pi(x, RoundNearest)` |
| 9 | + # to yield a very tight result. This is not guaranteed by Julia, see e.g. |
| 10 | + # https://github.com/JuliaLang/julia/blob/9669eecc99bc4553e28d94d7dd3dc9fd40b3bf3f/base/mpfr.jl#L845-L846 |
| 11 | + PI_LO, PI_HI = bounds(bareinterval(typeof(x), π)) |
8 | 12 | r = rem2pi(x, RoundNearest)
|
9 |
| - -2r > π && return 2 # [-π, -π/2) |
10 |
| - r < 0 && return 3 # [-π/2, 0) |
11 |
| - 2r < π && return 0 # [0, π/2) |
| 13 | + r2 = 2r # should be exact for floats |
| 14 | + r2 ≤ -PI_HI && return 2 # [-π, -π/2) |
| 15 | + r2 < -PI_LO && return throw(ArgumentError("could not determine the quadrant, the remainder $r of the division of $x by 2π is lesser or greater than -π/2")) |
| 16 | + r2 < 0 && return 3 # [-π/2, 0) |
| 17 | + r2 ≤ PI_LO && return 0 # [0, π/2) |
| 18 | + r2 < PI_HI && return throw(ArgumentError("could not determine the quadrant, the remainder $r of the division of $x by 2π is lesser or greater than π/2")) |
12 | 19 | return 1 # [π/2, π]
|
13 | 20 | end
|
14 | 21 |
|
15 | 22 | function _quadrantpi(x::AbstractFloat) # used in `sinpi` and `cospi`
|
16 |
| - r = rem(x, 2) |
| 23 | + r = rem(x, 2) # [-2, 2], should be exact for floats |
17 | 24 | 2r < -3 && return 0 # [-2π, -3π/2)
|
18 | 25 | r < -1 && return 1 # [-3π/2, -π)
|
19 | 26 | 2r < -1 && return 2 # [-π, -π/2)
|
@@ -52,16 +59,17 @@ Implement the `sin` function of the IEEE Standard 1788-2015 (Table 9.1).
|
52 | 59 | function Base.sin(x::BareInterval{T}) where {T<:AbstractFloat}
|
53 | 60 | isempty_interval(x) && return x
|
54 | 61 |
|
| 62 | + PI_HI = sup(bareinterval(T, π)) |
55 | 63 | d = diam(x)
|
56 |
| - d/2 ≥ π && return _unsafe_bareinterval(T, -one(T), one(T)) |
| 64 | + d ≥ 2PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) |
57 | 65 |
|
58 | 66 | lo, hi = bounds(x)
|
59 | 67 |
|
60 | 68 | lo_quadrant = _quadrant(lo)
|
61 | 69 | hi_quadrant = _quadrant(hi)
|
62 | 70 |
|
63 | 71 | if lo_quadrant == hi_quadrant
|
64 |
| - d ≥ π && return _unsafe_bareinterval(T, -one(T), one(T)) |
| 72 | + d ≥ PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) |
65 | 73 | (lo_quadrant == 1) | (lo_quadrant == 2) && return @round(T, sin(hi), sin(lo)) # decreasing
|
66 | 74 | return @round(T, sin(lo), sin(hi))
|
67 | 75 |
|
@@ -148,16 +156,17 @@ Implement the `cos` function of the IEEE Standard 1788-2015 (Table 9.1).
|
148 | 156 | function Base.cos(x::BareInterval{T}) where {T<:AbstractFloat}
|
149 | 157 | isempty_interval(x) && return x
|
150 | 158 |
|
| 159 | + PI_HI = sup(bareinterval(T, π)) |
151 | 160 | d = diam(x)
|
152 |
| - d/2 ≥ π && return _unsafe_bareinterval(T, -one(T), one(T)) |
| 161 | + d ≥ 2PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) |
153 | 162 |
|
154 | 163 | lo, hi = bounds(x)
|
155 | 164 |
|
156 | 165 | lo_quadrant = _quadrant(lo)
|
157 | 166 | hi_quadrant = _quadrant(hi)
|
158 | 167 |
|
159 | 168 | if lo_quadrant == hi_quadrant
|
160 |
| - d ≥ π && return _unsafe_bareinterval(T, -one(T), one(T)) |
| 169 | + d ≥ PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) |
161 | 170 | (lo_quadrant == 2) | (lo_quadrant == 3) && return @round(T, cos(lo), cos(hi)) # increasing
|
162 | 171 | return @round(T, cos(hi), cos(lo))
|
163 | 172 |
|
@@ -246,7 +255,7 @@ Implement the `tan` function of the IEEE Standard 1788-2015 (Table 9.1).
|
246 | 255 | function Base.tan(x::BareInterval{T}) where {T<:AbstractFloat}
|
247 | 256 | isempty_interval(x) && return x
|
248 | 257 |
|
249 |
| - diam(x) > π && return entireinterval(BareInterval{T}) |
| 258 | + diam(x) > sup(bareinterval(T, π)) && return entireinterval(BareInterval{T}) |
250 | 259 |
|
251 | 260 | lo, hi = bounds(x)
|
252 | 261 |
|
@@ -282,7 +291,7 @@ Implement the `cot` function of the IEEE Standard 1788-2015 (Table 9.1).
|
282 | 291 | function Base.cot(x::BareInterval{T}) where {T<:AbstractFloat}
|
283 | 292 | isempty_interval(x) && return x
|
284 | 293 |
|
285 |
| - diam(x) > π && return entireinterval(BareInterval{T}) |
| 294 | + diam(x) > sup(bareinterval(T, π)) && return entireinterval(BareInterval{T}) |
286 | 295 |
|
287 | 296 | isthinzero(x) && return emptyinterval(BareInterval{T})
|
288 | 297 |
|
@@ -316,7 +325,7 @@ Implement the `sec` function of the IEEE Standard 1788-2015 (Table 9.1).
|
316 | 325 | function Base.sec(x::BareInterval{T}) where {T<:AbstractFloat}
|
317 | 326 | isempty_interval(x) && return x
|
318 | 327 |
|
319 |
| - diam(x) > π && return entireinterval(BareInterval{T}) |
| 328 | + diam(x) > sup(bareinterval(T, π)) && return entireinterval(BareInterval{T}) |
320 | 329 |
|
321 | 330 | lo, hi = bounds(x)
|
322 | 331 |
|
@@ -352,7 +361,7 @@ Implement the `csc` function of the IEEE Standard 1788-2015 (Table 9.1).
|
352 | 361 | function Base.csc(x::BareInterval{T}) where {T<:AbstractFloat}
|
353 | 362 | isempty_interval(x) && return x
|
354 | 363 |
|
355 |
| - diam(x) > π && return entireinterval(BareInterval{T}) |
| 364 | + diam(x) > sup(bareinterval(T, π)) && return entireinterval(BareInterval{T}) |
356 | 365 |
|
357 | 366 | isthinzero(x) && return emptyinterval(BareInterval{T})
|
358 | 367 |
|
|
0 commit comments