Skip to content

Commit bb79e22

Browse files
authored
Fix quadrant (#652)
1 parent 96dedc6 commit bb79e22

File tree

1 file changed

+28
-25
lines changed

1 file changed

+28
-25
lines changed

src/intervals/arithmetic/trigonometric.jl

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,22 @@
44

55
# helper functions
66

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
2023
end
2124

2225
function _quadrantpi(x::AbstractFloat) # used in `sinpi` and `cospi`
@@ -65,8 +68,8 @@ function Base.sin(x::BareInterval{T}) where {T<:AbstractFloat}
6568

6669
lo, hi = bounds(x)
6770

68-
lo_quadrant = _quadrant(lo)
69-
hi_quadrant = _quadrant(hi)
71+
lo_quadrant = _quadrant(min, lo)
72+
hi_quadrant = _quadrant(max, hi)
7073

7174
if lo_quadrant == hi_quadrant
7275
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T))
@@ -167,8 +170,8 @@ function Base.cos(x::BareInterval{T}) where {T<:AbstractFloat}
167170

168171
lo, hi = bounds(x)
169172

170-
lo_quadrant = _quadrant(lo)
171-
hi_quadrant = _quadrant(hi)
173+
lo_quadrant = _quadrant(min, lo)
174+
hi_quadrant = _quadrant(max, hi)
172175

173176
if lo_quadrant == hi_quadrant
174177
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T))
@@ -269,8 +272,8 @@ function Base.tan(x::BareInterval{T}) where {T<:AbstractFloat}
269272

270273
lo, hi = bounds(x)
271274

272-
lo_quadrant = _quadrant(lo)
273-
hi_quadrant = _quadrant(hi)
275+
lo_quadrant = _quadrant(min, lo)
276+
hi_quadrant = _quadrant(max, hi)
274277
lo_quadrant_mod = mod(lo_quadrant, 2)
275278
hi_quadrant_mod = mod(hi_quadrant, 2)
276279

@@ -309,8 +312,8 @@ function Base.cot(x::BareInterval{T}) where {T<:AbstractFloat}
309312

310313
lo, hi = bounds(x)
311314

312-
lo_quadrant = _quadrant(lo)
313-
hi_quadrant = _quadrant(hi)
315+
lo_quadrant = _quadrant(min, lo)
316+
hi_quadrant = _quadrant(max, hi)
314317

315318
if (lo_quadrant == 2 || lo_quadrant == 3) && hi == 0
316319
return @round(T, typemin(T), cot(lo)) # singularity from the left
@@ -341,8 +344,8 @@ function Base.sec(x::BareInterval{T}) where {T<:AbstractFloat}
341344

342345
lo, hi = bounds(x)
343346

344-
lo_quadrant = _quadrant(lo)
345-
hi_quadrant = _quadrant(hi)
347+
lo_quadrant = _quadrant(min, lo)
348+
hi_quadrant = _quadrant(max, hi)
346349

347350
if lo_quadrant == hi_quadrant
348351
(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}
379382

380383
lo, hi = bounds(x)
381384

382-
lo_quadrant = _quadrant(lo)
383-
hi_quadrant = _quadrant(hi)
385+
lo_quadrant = _quadrant(min, lo)
386+
hi_quadrant = _quadrant(max, hi)
384387

385388
if (lo_quadrant == 2 || lo_quadrant == 3) && hi == 0
386389
# singularity from the left

0 commit comments

Comments
 (0)