|
4 | 4 |
|
5 | 5 | # helper functions |
6 | 6 |
|
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), π)) |
12 | | - r = rem2pi(x, RoundNearest) |
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")) |
19 | | - return 1 # [π/2, π] |
| 7 | +function _quadrant(f, x::T) where {T<:AbstractFloat} |
| 8 | + PI = bareinterval(T, π) |
| 9 | + PI_LO, PI_HI = bounds(PI) |
| 10 | + if abs(x) ≤ PI_LO # (-π, π) |
| 11 | + r2 = 2x # should be exact for floats |
| 12 | + r2 ≤ -PI_HI && return 2 # (-π, -π/2) |
| 13 | + r2 < -PI_LO && return f(2, 3) # (-π, -π/2) or [-π/2, 0) |
| 14 | + r2 < 0 && return 3 # [-π/2, 0) |
| 15 | + r2 ≤ PI_LO && return 0 # [0, π/2) |
| 16 | + r2 < PI_HI && return f(0, 1) # [0, π/2) or [π/2, π) |
| 17 | + return 1 # [π/2, π) |
| 18 | + else |
| 19 | + k = _unsafe_scale(bareinterval(x) / PI, convert(T, 2)) |
| 20 | + fk = floor(k) |
| 21 | + return f(mod(inf(fk), 4), mod(sup(fk), 4)) |
| 22 | + end |
20 | 23 | end |
21 | 24 |
|
22 | 25 | function _quadrantpi(x::AbstractFloat) # used in `sinpi` and `cospi` |
@@ -65,8 +68,8 @@ function Base.sin(x::BareInterval{T}) where {T<:AbstractFloat} |
65 | 68 |
|
66 | 69 | lo, hi = bounds(x) |
67 | 70 |
|
68 | | - lo_quadrant = _quadrant(lo) |
69 | | - hi_quadrant = _quadrant(hi) |
| 71 | + lo_quadrant = _quadrant(min, lo) |
| 72 | + hi_quadrant = _quadrant(max, hi) |
70 | 73 |
|
71 | 74 | if lo_quadrant == hi_quadrant |
72 | 75 | d ≥ PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) |
@@ -167,8 +170,8 @@ function Base.cos(x::BareInterval{T}) where {T<:AbstractFloat} |
167 | 170 |
|
168 | 171 | lo, hi = bounds(x) |
169 | 172 |
|
170 | | - lo_quadrant = _quadrant(lo) |
171 | | - hi_quadrant = _quadrant(hi) |
| 173 | + lo_quadrant = _quadrant(min, lo) |
| 174 | + hi_quadrant = _quadrant(max, hi) |
172 | 175 |
|
173 | 176 | if lo_quadrant == hi_quadrant |
174 | 177 | d ≥ PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) |
@@ -269,8 +272,8 @@ function Base.tan(x::BareInterval{T}) where {T<:AbstractFloat} |
269 | 272 |
|
270 | 273 | lo, hi = bounds(x) |
271 | 274 |
|
272 | | - lo_quadrant = _quadrant(lo) |
273 | | - hi_quadrant = _quadrant(hi) |
| 275 | + lo_quadrant = _quadrant(min, lo) |
| 276 | + hi_quadrant = _quadrant(max, hi) |
274 | 277 | lo_quadrant_mod = mod(lo_quadrant, 2) |
275 | 278 | hi_quadrant_mod = mod(hi_quadrant, 2) |
276 | 279 |
|
@@ -309,8 +312,8 @@ function Base.cot(x::BareInterval{T}) where {T<:AbstractFloat} |
309 | 312 |
|
310 | 313 | lo, hi = bounds(x) |
311 | 314 |
|
312 | | - lo_quadrant = _quadrant(lo) |
313 | | - hi_quadrant = _quadrant(hi) |
| 315 | + lo_quadrant = _quadrant(min, lo) |
| 316 | + hi_quadrant = _quadrant(max, hi) |
314 | 317 |
|
315 | 318 | if (lo_quadrant == 2 || lo_quadrant == 3) && hi == 0 |
316 | 319 | return @round(T, typemin(T), cot(lo)) # singularity from the left |
@@ -341,8 +344,8 @@ function Base.sec(x::BareInterval{T}) where {T<:AbstractFloat} |
341 | 344 |
|
342 | 345 | lo, hi = bounds(x) |
343 | 346 |
|
344 | | - lo_quadrant = _quadrant(lo) |
345 | | - hi_quadrant = _quadrant(hi) |
| 347 | + lo_quadrant = _quadrant(min, lo) |
| 348 | + hi_quadrant = _quadrant(max, hi) |
346 | 349 |
|
347 | 350 | if lo_quadrant == hi_quadrant |
348 | 351 | (lo_quadrant == 0) | (lo_quadrant == 1) && return @round(T, sec(lo), sec(hi)) # increasing |
@@ -379,8 +382,8 @@ function Base.csc(x::BareInterval{T}) where {T<:AbstractFloat} |
379 | 382 |
|
380 | 383 | lo, hi = bounds(x) |
381 | 384 |
|
382 | | - lo_quadrant = _quadrant(lo) |
383 | | - hi_quadrant = _quadrant(hi) |
| 385 | + lo_quadrant = _quadrant(min, lo) |
| 386 | + hi_quadrant = _quadrant(max, hi) |
384 | 387 |
|
385 | 388 | if (lo_quadrant == 2 || lo_quadrant == 3) && hi == 0 |
386 | 389 | # singularity from the left |
|
0 commit comments