Skip to content

Commit b5251ac

Browse files
authored
Fix quadrant (#684)
* Fix quadrant * Add test * Do not convert to `Int` * Use `floor` * Rework fix
1 parent fe4629d commit b5251ac

File tree

2 files changed

+16
-6
lines changed

2 files changed

+16
-6
lines changed

src/intervals/arithmetic/trigonometric.jl

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,17 @@ function _quadrant(f, x::T) where {T<:AbstractFloat}
99
PI_LO, PI_HI = bounds(PI)
1010
if abs(x) PI_LO # (-π, π)
1111
r2 = 2x # should be exact for floats
12-
r2 -PI_HI && return 2 # (-π, -π/2)
12+
r2 -PI_HI && return 2 # (-π, -π/2)
1313
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)
14+
r2 < 0 && return 3 # [-π/2, 0)
15+
r2 PI_LO && return 0 # [0, π/2)
1616
r2 < PI_HI && return f(0, 1) # [0, π/2) or [π/2, π)
1717
return 1 # [π/2, π)
1818
else
1919
k = _unsafe_scale(bareinterval(x) / PI, convert(T, 2))
2020
fk = floor(k)
21-
return f(mod(inf(fk), 4), mod(sup(fk), 4))
21+
lfk, hfk = bounds(fk)
22+
return f(Int(mod(lfk, 4)), Int(mod(hfk, 4)))
2223
end
2324
end
2425

@@ -72,14 +73,16 @@ function Base.sin(x::BareInterval{T}) where {T<:AbstractFloat}
7273
hi_quadrant = _quadrant(max, hi)
7374

7475
if lo_quadrant == hi_quadrant
75-
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T))
76+
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) # diameter ≥ 2π
7677
(lo_quadrant == 1) | (lo_quadrant == 2) && return @round(T, sin(hi), sin(lo)) # decreasing
7778
return @round(T, sin(lo), sin(hi))
7879

7980
elseif lo_quadrant == 3 && hi_quadrant == 0
81+
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) # diameter ≥ 3π/2
8082
return @round(T, sin(lo), sin(hi)) # increasing
8183

8284
elseif lo_quadrant == 1 && hi_quadrant == 2
85+
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) # diameter ≥ 3π/2
8386
return @round(T, sin(hi), sin(lo)) # decreasing
8487

8588
elseif (lo_quadrant == 0 || lo_quadrant == 3) && (hi_quadrant == 1 || hi_quadrant == 2)
@@ -174,14 +177,16 @@ function Base.cos(x::BareInterval{T}) where {T<:AbstractFloat}
174177
hi_quadrant = _quadrant(max, hi)
175178

176179
if lo_quadrant == hi_quadrant
177-
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T))
180+
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) # diameter ≥ 2π
178181
(lo_quadrant == 2) | (lo_quadrant == 3) && return @round(T, cos(lo), cos(hi)) # increasing
179182
return @round(T, cos(hi), cos(lo))
180183

181184
elseif lo_quadrant == 2 && hi_quadrant == 3
185+
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) # diameter ≥ 3π/2
182186
return @round(T, cos(lo), cos(hi))
183187

184188
elseif lo_quadrant == 0 && hi_quadrant == 1
189+
d PI_HI && return _unsafe_bareinterval(T, -one(T), one(T)) # diameter ≥ 3π/2
185190
return @round(T, cos(hi), cos(lo))
186191

187192
elseif (lo_quadrant == 2 || lo_quadrant == 3) && (hi_quadrant == 0 || hi_quadrant == 1)

test/interval_tests/trigonometric.jl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ end
3939
@test issubset_interval(cos(interval(BigFloat, 0.5, 8.5)), cos(interval(0.5, 8.5)))
4040
@test issubset_interval(cos(interval(BigFloat, -4.5, 0.1)), cos(interval(-4.5, 0.1)))
4141
@test issubset_interval(cos(interval(BigFloat, 1.3, 6.3)), cos(interval(1.3, 6.3)))
42+
43+
k = [interval(0.0,0.0625), interval(0.0625,0.125), interval(0.0,0.125)]
44+
x = (k[1] * 4 + k[2] * 4 + k[3] * 4)
45+
@test isequal_interval(cos(2 * π * x), interval(-1, 1))
46+
@test isequal_interval(cospi(2x), interval(-1, 1))
4247
end
4348

4449
@testset "sinpi" begin

0 commit comments

Comments
 (0)