1use crate::{classify::*, interval::*, simd::*};
2use forward_ref::*;
3use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
4
5impl Neg for Interval {
6 type Output = Self;
7
8 fn neg(self) -> Self {
9 Self {
11 rep: swap(self.rep),
12 }
13 }
14}
15
16forward_ref_unop!(impl Neg, neg for Interval);
17
18impl Add for Interval {
19 type Output = Self;
20
21 fn add(self, rhs: Self) -> Self {
22 let x = self.rep; let y = rhs.rep; Self { rep: add_ru(x, y) }
26 }
27}
28
29forward_ref_binop!(impl Add, add for Interval, Interval);
30
31impl Sub for Interval {
32 type Output = Self;
33
34 fn sub(self, rhs: Self) -> Self {
35 let x = self.rep; let y = swap(rhs.rep); Self { rep: add_ru(x, y) }
39 }
40}
41
42forward_ref_binop!(impl Sub, sub for Interval, Interval);
43
44impl Mul for Interval {
45 type Output = Self;
46
47 #[allow(clippy::many_single_char_names)]
48 fn mul(self, rhs: Self) -> Self {
49 use IntervalClass2::*;
60 match self.classify2(rhs) {
61 E_E | E_M | E_N0 | E_N1 | E_P0 | E_P1 | E_Z | M_E | N0_E | N1_E | P0_E | P1_E | Z_E => {
62 Self::EMPTY
63 }
64 M_Z | N0_Z | N1_Z | P0_Z | P1_Z | Z_M | Z_N0 | Z_N1 | Z_P0 | Z_P1 | Z_Z => Self::zero(),
65 M_M => {
66 let x = shuffle02(self.rep, self.rep); let y = swap(rhs.rep); let xy = mul_ru(x, y);
75 let z = shuffle13(self.rep, self.rep); let w = rhs.rep; let zw = mul_ru(z, w);
78 let r = max(xy, zw);
79 Self { rep: r }
80 }
81 M_N0 | M_N1 => {
82 let x = swap(self.rep); let y = shuffle02(rhs.rep, rhs.rep); Self { rep: mul_ru(x, y) }
86 }
87 M_P0 | M_P1 => {
88 let x = self.rep; let y = shuffle13(rhs.rep, rhs.rep); Self { rep: mul_ru(x, y) }
92 }
93 N0_M | N1_M => {
94 let x = shuffle02(self.rep, self.rep); let y = swap(rhs.rep); Self { rep: mul_ru(x, y) }
98 }
99 N0_N0 | N0_N1 | N1_N0 | N1_N1 => {
100 let x = swap(self.rep); let x = neg0(x); let y = swap(rhs.rep); Self { rep: mul_ru(x, y) }
105 }
106 N0_P0 | N0_P1 | N1_P0 | N1_P1 => {
107 let x = self.rep; let y = neg0(rhs.rep); let y = swap(y); Self { rep: mul_ru(x, y) }
112 }
113 P0_M | P1_M => {
114 let x = shuffle13(self.rep, self.rep); let y = rhs.rep; Self { rep: mul_ru(x, y) }
118 }
119 P0_N0 | P0_N1 | P1_N0 | P1_N1 => {
120 let x = neg0(self.rep); let x = swap(x); let y = rhs.rep; Self { rep: mul_ru(x, y) }
125 }
126 P0_P0 | P0_P1 | P1_P0 | P1_P1 => {
127 let x = self.rep; let y = neg0(rhs.rep); Self { rep: mul_ru(x, y) }
131 }
132 }
133 }
134}
135
136forward_ref_binop!(impl Mul, mul for Interval, Interval);
137
138impl Div for Interval {
139 type Output = Self;
140
141 fn div(self, rhs: Self) -> Self {
142 use IntervalClass2::*;
152 match self.classify2(rhs) {
153 E_E | E_M | E_N0 | E_N1 | E_P0 | E_P1 | E_Z | M_E | M_Z | N0_E | N0_Z | N1_E | N1_Z
154 | P0_E | P0_Z | P1_E | P1_Z | Z_E | Z_Z => Self::EMPTY,
155 M_M | M_N0 | M_P0 | N0_M | N1_M | P0_M | P1_M => Self::ENTIRE,
156 Z_M | Z_N0 | Z_N1 | Z_P0 | Z_P1 => Self::zero(),
157 M_N1 => self.div_m_n1(rhs),
158 M_P1 => self.div_m_p1(rhs),
159 N0_N0 | N1_N0 => self.div_n_n0(rhs),
160 N0_N1 | N1_N1 => self.div_n_n1(rhs),
161 N0_P0 | N1_P0 => self.div_n_p0(rhs),
162 N0_P1 | N1_P1 => self.div_n_p1(rhs),
163 P0_N0 | P1_N0 => self.div_p_n0(rhs),
164 P0_N1 | P1_N1 => self.div_p_n1(rhs),
165 P0_P0 | P1_P0 => self.div_p_p0(rhs),
166 P0_P1 | P1_P1 => self.div_p_p1(rhs),
167 }
168 }
169}
170
171forward_ref_binop!(impl Div, div for Interval, Interval);
172
173impl Neg for DecInterval {
174 type Output = Self;
175
176 fn neg(self) -> Self {
177 if self.is_nai() {
178 return self;
179 }
180
181 Self::set_dec(-self.x, self.d)
182 }
183}
184
185forward_ref_unop!(impl Neg, neg for DecInterval);
186
187impl Add for DecInterval {
188 type Output = Self;
189
190 fn add(self, rhs: Self) -> Self {
191 if self.is_nai() || rhs.is_nai() {
192 return Self::NAI;
193 }
194
195 Self::set_dec(self.x + rhs.x, self.d.min(rhs.d))
196 }
197}
198
199forward_ref_binop!(impl Add, add for DecInterval, DecInterval);
200
201impl Sub for DecInterval {
202 type Output = Self;
203
204 fn sub(self, rhs: Self) -> Self {
205 if self.is_nai() || rhs.is_nai() {
206 return Self::NAI;
207 }
208
209 Self::set_dec(self.x - rhs.x, self.d.min(rhs.d))
210 }
211}
212
213forward_ref_binop!(impl Sub, sub for DecInterval, DecInterval);
214
215impl Mul for DecInterval {
216 type Output = Self;
217
218 fn mul(self, rhs: Self) -> Self {
219 if self.is_nai() || rhs.is_nai() {
220 return Self::NAI;
221 }
222
223 Self::set_dec(self.x * rhs.x, self.d.min(rhs.d))
224 }
225}
226
227forward_ref_binop!(impl Mul, mul for DecInterval, DecInterval);
228
229impl Div for DecInterval {
230 type Output = Self;
231
232 fn div(self, rhs: Self) -> Self {
233 if self.is_nai() || rhs.is_nai() {
234 return Self::NAI;
235 }
236
237 let d = if rhs.x.contains(0.0) {
238 Decoration::Trv
239 } else {
240 self.d.min(rhs.d)
241 };
242 Self::set_dec(self.x / rhs.x, d)
243 }
244}
245
246forward_ref_binop!(impl Div, div for DecInterval, DecInterval);
247
248macro_rules! impl_op_assign {
249 ($OpAssign:ident, $op_assign:ident, $op:ident) => {
250 impl $OpAssign for Interval {
251 fn $op_assign(&mut self, rhs: Self) {
252 *self = self.$op(rhs);
253 }
254 }
255
256 forward_ref_op_assign!(impl $OpAssign, $op_assign for Interval,
257 Interval);
258
259 impl $OpAssign for DecInterval {
260 fn $op_assign(&mut self, rhs: Self) {
261 *self = self.$op(rhs);
262 }
263 }
264
265 forward_ref_op_assign!(impl $OpAssign, $op_assign for DecInterval,
266 DecInterval);
267 };
268}
269
270impl_op_assign!(AddAssign, add_assign, add);
271impl_op_assign!(SubAssign, sub_assign, sub);
272impl_op_assign!(MulAssign, mul_assign, mul);
273impl_op_assign!(DivAssign, div_assign, div);
274
275#[cfg(test)]
276mod tests {
277 use crate::*;
278 use DecInterval as DI;
279 use Interval as I;
280
281 #[test]
282 fn add_assign() {
283 let mut i = const_interval!(3.0, 4.0);
284 i += const_interval!(1.0, 2.0);
285 assert_eq!(i, const_interval!(4.0, 6.0));
286
287 let mut i = const_dec_interval!(3.0, 4.0);
288 i += const_dec_interval!(1.0, 2.0);
289 assert_eq!(i, const_dec_interval!(4.0, 6.0));
290 }
291
292 #[test]
293 fn sub_assign() {
294 let mut i = const_interval!(3.0, 4.0);
295 i -= const_interval!(1.0, 2.0);
296 assert_eq!(i, const_interval!(1.0, 3.0));
297
298 let mut i = const_dec_interval!(3.0, 4.0);
299 i -= const_dec_interval!(1.0, 2.0);
300 assert_eq!(i, const_dec_interval!(1.0, 3.0));
301 }
302
303 #[test]
304 fn mul_assign() {
305 let mut i = const_interval!(3.0, 4.0);
306 i *= const_interval!(1.0, 2.0);
307 assert_eq!(i, const_interval!(3.0, 8.0));
308
309 let mut i = const_dec_interval!(3.0, 4.0);
310 i *= const_dec_interval!(1.0, 2.0);
311 assert_eq!(i, const_dec_interval!(3.0, 8.0));
312 }
313
314 #[test]
315 fn div_assign() {
316 let mut i = const_interval!(3.0, 4.0);
317 i /= const_interval!(1.0, 2.0);
318 assert_eq!(i, const_interval!(1.5, 4.0));
319
320 let mut i = const_dec_interval!(3.0, 4.0);
321 i /= const_dec_interval!(1.0, 2.0);
322 assert_eq!(i, const_dec_interval!(1.5, 4.0));
323 }
324
325 #[test]
326 fn empty() {
327 assert!((-I::EMPTY).is_empty());
328
329 assert!((I::EMPTY + I::PI).is_empty());
330 assert!((I::PI + I::EMPTY).is_empty());
331
332 assert!((I::EMPTY - I::PI).is_empty());
333 assert!((I::PI - I::EMPTY).is_empty());
334
335 assert!((I::EMPTY * I::PI).is_empty());
336 assert!((I::PI * I::EMPTY).is_empty());
337
338 assert!((I::EMPTY / I::PI).is_empty());
339 assert!((I::PI / I::EMPTY).is_empty());
340
341 assert!((-DI::EMPTY).is_empty());
342
343 assert!((DI::EMPTY + DI::PI).is_empty());
344 assert!((DI::PI + DI::EMPTY).is_empty());
345
346 assert!((DI::EMPTY - DI::PI).is_empty());
347 assert!((DI::PI - DI::EMPTY).is_empty());
348
349 assert!((DI::EMPTY * DI::PI).is_empty());
350 assert!((DI::PI * DI::EMPTY).is_empty());
351
352 assert!((DI::EMPTY / DI::PI).is_empty());
353 assert!((DI::PI / DI::EMPTY).is_empty());
354 }
355
356 #[test]
357 fn nai() {
358 assert!((-DI::NAI).is_nai());
359
360 assert!((DI::NAI + DI::PI).is_nai());
361 assert!((DI::PI + DI::NAI).is_nai());
362
363 assert!((DI::NAI - DI::PI).is_nai());
364 assert!((DI::PI - DI::NAI).is_nai());
365
366 assert!((DI::NAI * DI::PI).is_nai());
367 assert!((DI::PI * DI::NAI).is_nai());
368
369 assert!((DI::NAI / DI::PI).is_nai());
370 assert!((DI::PI / DI::NAI).is_nai());
371 }
372
373 #[allow(clippy::op_ref)]
374 #[test]
375 fn ref_type_args() {
376 const E: I = I::EMPTY;
377 const DE: DI = DI::EMPTY;
378
379 let _ = -&E;
380
381 let _ = &E + E;
382 let _ = E + &E;
383 let _ = &E + &E;
384
385 let _ = &E - E;
386 let _ = E - &E;
387 let _ = &E - &E;
388
389 let _ = &E * E;
390 let _ = E * &E;
391 let _ = &E * &E;
392
393 let _ = &E / E;
394 let _ = E / &E;
395 let _ = &E / &E;
396
397 let _ = -&DE;
398
399 let _ = &DE + DE;
400 let _ = DE + &DE;
401 let _ = &DE + &DE;
402
403 let _ = &DE - DE;
404 let _ = DE - &DE;
405 let _ = &DE - &DE;
406
407 let _ = &DE * DE;
408 let _ = DE * &DE;
409 let _ = &DE * &DE;
410
411 let _ = &DE / DE;
412 let _ = DE / &DE;
413 let _ = &DE / &DE;
414
415 let mut e = I::EMPTY;
416 e += &E;
417 e -= &E;
418 e *= &E;
419 e /= &E;
420
421 let mut de = DI::EMPTY;
422 de += &DE;
423 de -= &DE;
424 de *= &DE;
425 de /= &DE;
426 }
427}