@@ -21,6 +21,7 @@ range_atan(::Type{T}) where {T<:Real} = Interval(-(pi_interval(T).hi), pi_interv
21
21
half_range_atan (:: Type{T} ) where {T} = (temp = half_pi (T); Interval (- (temp. hi), temp. hi) )
22
22
pos_range_atan (:: Type{T} ) where {T<: Real } = Interval (zero (T), pi_interval (T). hi)
23
23
24
+ const halfpi = pi / 2.0
24
25
25
26
""" Finds the quadrant(s) corresponding to a given floating-point
26
27
number. The quadrants are labelled as 0 for x ∈ [0, π/2], etc.
@@ -37,13 +38,6 @@ function find_quadrants(x::T) where {T}
37
38
return SVector (floor (temp. lo), floor (temp. hi))
38
39
end
39
40
40
- function find_quadrants (x:: Float64 )
41
- temp = multiply_by_positive_constant (x, one_over_half_pi_interval)
42
- # x / half_pi(Float64)
43
-
44
- return SVector (floor (temp. lo), floor (temp. hi))
45
- end
46
-
47
41
function sin (a:: Interval{T} ) where T
48
42
isempty (a) && return a
49
43
@@ -89,6 +83,60 @@ function sin(a::Interval{T}) where T
89
83
end
90
84
end
91
85
86
+ function quadrant (x:: Float64 )
87
+ x_mod2pi = rem2pi (x, RoundNearest) # gives result in [-pi, pi]
88
+
89
+ x_mod2pi < - halfpi && return (2 , x_mod2pi)
90
+ x_mod2pi < 0 && return (3 , x_mod2pi)
91
+ x_mod2pi <= halfpi && return (0 , x_mod2pi)
92
+
93
+ return 1 , x_mod2pi
94
+ end
95
+
96
+
97
+ function sin (a:: Interval{Float64} )
98
+
99
+ T = Float64
100
+
101
+ isempty (a) && return a
102
+
103
+ whole_range = Interval {T} (- 1 , 1 )
104
+
105
+ diam (a) > two_pi (T). lo && return whole_range
106
+
107
+ lo_quadrant, lo = quadrant (a. lo)
108
+ hi_quadrant, hi = quadrant (a. hi)
109
+
110
+ lo, hi = a. lo, a. hi # should be able to use the modulo version of a, but doesn't seem to work
111
+
112
+ # Different cases depending on the two quadrants:
113
+ if lo_quadrant == hi_quadrant
114
+ a. hi - a. lo > pi_interval (T). lo && return whole_range #
115
+
116
+ if lo_quadrant == 1 || lo_quadrant == 2
117
+ # negative slope
118
+ return @round (sin (hi), sin (lo))
119
+ else
120
+ return @round (sin (lo), sin (hi))
121
+ end
122
+
123
+ elseif lo_quadrant== 3 && hi_quadrant== 0
124
+ return @round (sin (lo), sin (hi))
125
+
126
+ elseif lo_quadrant== 1 && hi_quadrant== 2
127
+ return @round (sin (hi), sin (lo))
128
+
129
+ elseif ( lo_quadrant == 0 || lo_quadrant== 3 ) && ( hi_quadrant== 1 || hi_quadrant== 2 )
130
+ return @round (min (sin (lo), sin (hi)), 1 )
131
+
132
+ elseif ( lo_quadrant == 1 || lo_quadrant== 2 ) && ( hi_quadrant== 3 || hi_quadrant== 0 )
133
+ return @round (- 1 , max (sin (lo), sin (hi)))
134
+
135
+ else # if( lo_quadrant == 0 && hi_quadrant==3 ) || ( lo_quadrant == 2 && hi_quadrant==1 )
136
+ return whole_range
137
+ end
138
+ end
139
+
92
140
93
141
function cos (a:: Interval{T} ) where T
94
142
isempty (a) && return a
@@ -131,6 +179,50 @@ function cos(a::Interval{T}) where T
131
179
end
132
180
end
133
181
182
+ function cos (a:: Interval{Float64} )
183
+
184
+ T = Float64
185
+
186
+ isempty (a) && return a
187
+
188
+ whole_range = Interval {Float64} (- one (T), one (T))
189
+
190
+ diam (a) > two_pi (T). lo && return whole_range
191
+
192
+ lo_quadrant, lo = quadrant (a. lo)
193
+ hi_quadrant, hi = quadrant (a. hi)
194
+
195
+ lo, hi = a. lo, a. hi
196
+
197
+ # Different cases depending on the two quadrants:
198
+ if lo_quadrant == hi_quadrant # Interval limits in the same quadrant
199
+ a. hi - a. lo > pi_interval (T). lo && return whole_range
200
+
201
+ if lo_quadrant == 2 || lo_quadrant == 3
202
+ # positive slope
203
+ return @round (cos (lo), cos (hi))
204
+ else
205
+ return @round (cos (hi), cos (lo))
206
+ end
207
+
208
+ elseif lo_quadrant == 2 && hi_quadrant== 3
209
+ return @round (cos (a. lo), cos (a. hi))
210
+
211
+ elseif lo_quadrant == 0 && hi_quadrant== 1
212
+ return @round (cos (a. hi), cos (a. lo))
213
+
214
+ elseif ( lo_quadrant == 2 || lo_quadrant== 3 ) && ( hi_quadrant== 0 || hi_quadrant== 1 )
215
+ return @round (min (cos (a. lo), cos (a. hi)), 1 )
216
+
217
+ elseif ( lo_quadrant == 0 || lo_quadrant== 1 ) && ( hi_quadrant== 2 || hi_quadrant== 3 )
218
+ return @round (- 1 , max (cos (a. lo), cos (a. hi)))
219
+
220
+ else # if ( lo_quadrant == 3 && hi_quadrant==2 ) || ( lo_quadrant == 1 && hi_quadrant==0 )
221
+ return whole_range
222
+ end
223
+ end
224
+
225
+
134
226
function find_quadrants_tan (x:: T ) where {T}
135
227
temp = atomic (Interval{T}, x) / half_pi (x)
136
228
@@ -166,6 +258,32 @@ function tan(a::Interval{T}) where T
166
258
return @round (tan (a. lo), tan (a. hi))
167
259
end
168
260
261
+ function tan (a:: Interval{Float64} )
262
+
263
+ T = Float64
264
+
265
+ isempty (a) && return a
266
+
267
+ diam (a) > pi_interval (T). lo && return entireinterval (a)
268
+
269
+ lo_quadrant, lo = quadrant (a. lo)
270
+ hi_quadrant, hi = quadrant (a. hi)
271
+
272
+ lo_quadrant_mod = mod (lo_quadrant, 2 )
273
+ hi_quadrant_mod = mod (hi_quadrant, 2 )
274
+
275
+ if lo_quadrant_mod == 0 && hi_quadrant_mod == 1
276
+ return entireinterval (a) # crosses singularity
277
+
278
+ elseif lo_quadrant_mod == hi_quadrant_mod && hi_quadrant != lo_quadrant
279
+ # must cross singularity
280
+ return entireinterval (a)
281
+
282
+ end
283
+
284
+ return @round (tan (a. lo), tan (a. hi))
285
+ end
286
+
169
287
function asin (a:: Interval{T} ) where T
170
288
171
289
domain = Interval (- one (T), one (T))
0 commit comments