relp_num/rational/small/ops/
mod.rs

1use std::cmp::Ordering;
2use std::iter::Sum;
3use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
4use std::ops::Neg;
5
6use crate::Negateable;
7use crate::non_zero::NonZero;
8use crate::non_zero::NonZeroSign;
9use crate::rational::small::{Rational128, Rational16, Rational32, Rational64, Rational8, RationalUsize};
10use crate::rational::small::{NonZeroRational128, NonZeroRational16, NonZeroRational32, NonZeroRational64, NonZeroRational8, NonZeroRationalUsize};
11use crate::rational::small::ops::building_blocks::{add128, add16, add32, add64, add8, add_usize};
12use crate::rational::small::ops::building_blocks::{sub128, sub16, sub32, sub64, sub8, sub_usize};
13use crate::rational::small::ops::building_blocks::{mul128, mul16, mul32, mul64, mul8, mul_usize};
14use crate::rational::small::ops::building_blocks::SignChange;
15use crate::sign::Sign;
16
17pub(crate) mod building_blocks;
18mod with_int;
19mod with_one;
20mod with_zero;
21
22#[cfg(test)]
23mod test;
24
25macro_rules! rational {
26    ($name:ident, $add_name:ident, $sub_name:ident, $mul_name:ident) => {
27        impl AddAssign<&$name> for $name {
28            #[inline]
29            fn add_assign(&mut self, rhs: &Self) {
30                match (self.sign, rhs.sign) {
31                    (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
32                        $add_name(
33                            &mut self.numerator,
34                            &mut self.denominator,
35                            rhs.numerator,
36                            rhs.denominator,
37                        )
38                    }
39                    (Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => {
40                        let sign_change = $sub_name(
41                            &mut self.numerator,
42                            &mut self.denominator,
43                            rhs.numerator,
44                            rhs.denominator,
45                        );
46                        match sign_change {
47                            SignChange::None => {}
48                            SignChange::Flip => self.sign.negate(),
49                            SignChange::Zero => self.sign = Sign::Zero,
50                        }
51                    }
52                    (_, Sign::Zero) => {},
53                    (Sign::Zero, _) => {
54                        *self = Self {
55                            sign: rhs.sign,
56                            numerator: rhs.numerator,
57                            denominator: rhs.denominator,
58                        };
59                    },
60                }
61            }
62        }
63
64        impl SubAssign<&$name> for $name {
65            #[inline]
66            fn sub_assign(&mut self, rhs: &Self) {
67                match (self.sign, rhs.sign) {
68                    (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
69                        let sign_change = $sub_name(
70                            &mut self.numerator,
71                            &mut self.denominator,
72                            rhs.numerator,
73                            rhs.denominator,
74                        );
75                        match sign_change {
76                            SignChange::None => {}
77                            SignChange::Flip => self.sign.negate(),
78                            SignChange::Zero => self.sign = Sign::Zero,
79                        }
80                    }
81                    (Sign::Positive, Sign::Negative) | (Sign::Negative, Sign::Positive) => {
82                        $add_name(
83                            &mut self.numerator,
84                            &mut self.denominator,
85                            rhs.numerator,
86                            rhs.denominator,
87                        )
88                    }
89                    (_, Sign::Zero) => {}
90                    (Sign::Zero, _) => {
91                        *self = Self {
92                            sign: !rhs.sign,
93                            numerator: rhs.numerator,
94                            denominator: rhs.denominator,
95                        };
96                    }
97                }
98            }
99        }
100
101        impl Sum for $name {
102            fn sum<I: Iterator<Item=Self>>(mut iter: I) -> Self {
103                let first_value = iter.next();
104                match first_value {
105                    None => <Self as num_traits::Zero>::zero(),
106                    Some(mut total) => {
107
108                        while let Some(next_value) = iter.next() {
109                            total += next_value;
110                        }
111
112                        total
113                    }
114                }
115            }
116        }
117
118        impl MulAssign<&$name> for $name {
119            #[inline]
120            fn mul_assign(&mut self, rhs: &Self) {
121                match (self.sign, rhs.sign) {
122                    (Sign::Positive | Sign::Negative, Sign::Positive | Sign::Negative) => {
123                        self.sign *= rhs.sign;
124                        $mul_name(&mut self.numerator, &mut self.denominator, rhs.numerator, rhs.denominator);
125                    }
126                    (Sign::Zero, _) => {}
127                    (_, Sign::Zero) => <Self as num_traits::Zero>::set_zero(self),
128                }
129            }
130        }
131
132        impl Div<$name> for &$name {
133            type Output = $name;
134
135            #[must_use]
136            #[inline]
137            fn div(self, mut rhs: $name) -> Self::Output {
138                match (self.sign, rhs.sign) {
139                    (Sign::Positive | Sign::Negative, Sign::Positive | Sign::Negative) => {
140                        let sign = self.sign * rhs.sign;
141                        $mul_name(&mut rhs.numerator, &mut rhs.denominator, self.denominator, self.numerator);
142                        Self::Output {
143                            sign,
144                            numerator: rhs.denominator,
145                            denominator: rhs.numerator,
146                        }
147                    }
148                    (_, Sign::Zero) => panic!(),
149                    (Sign::Zero, _) => {
150                        <$name as num_traits::Zero>::set_zero(&mut rhs);
151                        rhs
152                    }
153                }
154            }
155        }
156
157        impl DivAssign<&$name> for $name {
158            #[inline]
159            fn div_assign(&mut self, rhs: &Self) {
160                match (self.sign, rhs.sign) {
161                    (Sign::Positive | Sign::Negative, Sign::Positive | Sign::Negative) => {
162                        self.sign *= rhs.sign;
163                        $mul_name(&mut self.numerator, &mut self.denominator, rhs.denominator, rhs.numerator);
164                    }
165                    (_, Sign::Zero) => panic!(),
166                    (Sign::Zero, _) => {}
167                }
168            }
169        }
170    }
171}
172
173rational!(Rational8, add8, sub8, mul8);
174rational!(Rational16, add16, sub16, mul16);
175rational!(Rational32, add32, sub32, mul32);
176rational!(Rational64, add64, sub64, mul64);
177rational!(Rational128, add128, sub128, mul128);
178rational!(RationalUsize, add_usize, sub_usize, mul_usize);
179
180macro_rules! rational_non_zero {
181    ($name:ident, $add_name:ident, $sub_name:ident, $mul_name:ident) => {
182        impl AddAssign<&$name> for $name {
183            #[inline]
184            fn add_assign(&mut self, rhs: &Self) {
185                match (self.sign, rhs.sign) {
186                    (NonZeroSign::Positive, NonZeroSign::Positive) | (NonZeroSign::Negative, NonZeroSign::Negative) => {
187                        $add_name(
188                            &mut self.numerator,
189                            &mut self.denominator,
190                            rhs.numerator,
191                            rhs.denominator,
192                        )
193                    }
194                    (NonZeroSign::Positive, NonZeroSign::Negative) | (NonZeroSign::Negative, NonZeroSign::Positive) => {
195                        let sign_change = $sub_name(
196                            &mut self.numerator,
197                            &mut self.denominator,
198                            rhs.numerator,
199                            rhs.denominator,
200                        );
201                        match sign_change {
202                            SignChange::None => {}
203                            SignChange::Flip => self.sign.negate(),
204                            SignChange::Zero => panic!("attempt to add with overflow"),
205                        }
206                    }
207                }
208            }
209        }
210        impl SubAssign<&$name> for $name {
211            #[inline]
212            fn sub_assign(&mut self, rhs: &Self) {
213                match (self.sign, rhs.sign) {
214                    (NonZeroSign::Positive, NonZeroSign::Positive) | (NonZeroSign::Negative, NonZeroSign::Negative) => {
215                        let sign_change = $sub_name(
216                            &mut self.numerator,
217                            &mut self.denominator,
218                            rhs.numerator,
219                            rhs.denominator,
220                        );
221                        match sign_change {
222                            SignChange::None => {}
223                            SignChange::Flip => self.sign.negate(),
224                            SignChange::Zero => panic!("attempt to subtract with overflow"),
225                        }
226                    }
227                    (NonZeroSign::Positive, NonZeroSign::Negative) | (NonZeroSign::Negative, NonZeroSign::Positive) => {
228                        $add_name(
229                            &mut self.numerator,
230                            &mut self.denominator,
231                            rhs.numerator,
232                            rhs.denominator,
233                        )
234                    }
235                }
236            }
237        }
238        impl MulAssign<&$name> for $name {
239            #[inline]
240            fn mul_assign(&mut self, rhs: &Self) {
241                self.sign *= rhs.sign;
242                $mul_name(&mut self.numerator, &mut self.denominator, rhs.numerator, rhs.denominator);
243            }
244        }
245        impl Div<$name> for &$name {
246            type Output = $name;
247
248            #[must_use]
249            #[inline]
250            fn div(self, mut rhs: $name) -> Self::Output {
251                let sign = self.sign * rhs.sign;
252                $mul_name(&mut rhs.numerator, &mut rhs.denominator, self.denominator, self.numerator);
253                Self::Output {
254                    sign,
255                    numerator: rhs.denominator,
256                    denominator: rhs.numerator,
257                }
258            }
259        }
260        impl DivAssign<&$name> for $name {
261            #[inline]
262            fn div_assign(&mut self, rhs: &Self) {
263                self.sign *= rhs.sign;
264                $mul_name(&mut self.numerator, &mut self.denominator, rhs.denominator, rhs.numerator);
265            }
266        }
267
268        impl Neg for $name {
269            type Output = Self;
270
271            #[must_use]
272            #[inline]
273            fn neg(mut self) -> Self::Output {
274                self.sign.negate();
275                self
276            }
277        }
278
279        impl Neg for &$name {
280            type Output = $name;
281
282            #[must_use]
283            #[inline]
284            fn neg(self) -> Self::Output {
285                Self::Output {
286                    sign: !self.sign,
287                    numerator: self.numerator,
288                    denominator: self.denominator,
289                }
290            }
291        }
292    }
293}
294rational_non_zero!(NonZeroRational8, add8, sub8, mul8);
295rational_non_zero!(NonZeroRational16, add16, sub16, mul16);
296rational_non_zero!(NonZeroRational32, add32, sub32, mul32);
297rational_non_zero!(NonZeroRational64, add64, sub64, mul64);
298rational_non_zero!(NonZeroRational128, add128, sub128, mul128);
299rational_non_zero!(NonZeroRationalUsize, add_usize, sub_usize, mul_usize);
300
301macro_rules! rational_requiring_wide {
302    ($name:ident, $uty:ty, $BITS:literal, $wide:ty, $sign:ident) => {
303        impl Ord for $name {
304            #[must_use]
305            #[inline]
306            fn cmp(&self, other: &Self) -> Ordering {
307                self.partial_cmp(other).unwrap()
308            }
309        }
310
311        impl PartialOrd for $name {
312            #[must_use]
313            #[inline]
314            #[allow(unreachable_patterns)]
315            fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
316                self.sign.partial_cmp(&other.sign).or_else(|| {
317                    debug_assert_eq!(self.sign, other.sign);
318                    debug_assert!(self.is_not_zero());
319
320                    let widening_mul = |left, right| {
321                        let wide = unsafe { (left as $wide).unchecked_mul(right as $wide) };
322                        ((wide >> $BITS) as $uty, wide as $uty)
323                    };
324
325                    let ad = widening_mul(self.numerator, other.denominator);
326                    let bc = widening_mul(self.denominator, other.numerator);
327
328                    Some(match (ad.cmp(&bc), self.sign) {
329                        (Ordering::Less, $sign::Positive) | (Ordering::Greater, $sign::Negative) => Ordering::Less,
330                        (Ordering::Equal, _) => Ordering::Equal,
331                        (Ordering::Greater, $sign::Positive) | (Ordering::Less, $sign::Negative) => Ordering::Greater,
332                        _ => panic!("Zero case would have been equal or nonzero type"),
333                    })
334                })
335            }
336        }
337    }
338}
339rational_requiring_wide!(Rational8, u8, 8, u16, Sign);
340rational_requiring_wide!(Rational16, u16, 16, u32, Sign);
341rational_requiring_wide!(Rational32, u32, 32, u64, Sign);
342rational_requiring_wide!(Rational64, u64, 64, u128, Sign);
343rational_requiring_wide!(NonZeroRational8, u8, 8, u16, NonZeroSign);
344rational_requiring_wide!(NonZeroRational16, u16, 16, u32, NonZeroSign);
345rational_requiring_wide!(NonZeroRational32, u32, 32, u64, NonZeroSign);
346rational_requiring_wide!(NonZeroRational64, u64, 64, u128, NonZeroSign);
347
348macro_rules! rational_forward {
349    ($name:ident) => {
350        impl<'a> Add<&'a $name> for &'a $name {
351            type Output = $name;
352
353            #[must_use]
354            #[inline]
355            fn add(self, rhs: Self) -> Self::Output {
356                Add::add(self.clone(), rhs)
357            }
358        }
359
360        impl Add for $name {
361            type Output = Self;
362
363            #[must_use]
364            #[inline]
365            fn add(mut self, rhs: Self) -> Self::Output {
366                AddAssign::add_assign(&mut self, rhs);
367                self
368            }
369        }
370
371        impl Add<&$name> for $name {
372            type Output = Self;
373
374            #[must_use]
375            #[inline]
376            fn add(mut self, rhs: &Self) -> Self::Output {
377                AddAssign::add_assign(&mut self, rhs);
378                self
379            }
380        }
381
382        impl Add<$name> for &$name {
383            type Output = $name;
384
385            #[must_use]
386            #[inline]
387            fn add(self, rhs: $name) -> Self::Output {
388                Add::add(rhs, self)
389            }
390        }
391
392        impl AddAssign for $name {
393            #[inline]
394            fn add_assign(&mut self, rhs: Self) {
395                AddAssign::add_assign(self, &rhs);
396            }
397        }
398
399        impl Sub for $name {
400            type Output = Self;
401
402            #[must_use]
403            #[inline]
404            fn sub(mut self, rhs: Self) -> Self::Output {
405                SubAssign::sub_assign(&mut self, rhs);
406                self
407            }
408        }
409
410        impl<'a> Sub<&'a $name> for &'a $name {
411            type Output = $name;
412
413            #[must_use]
414            #[inline]
415            fn sub(self, rhs: Self) -> Self::Output {
416                Sub::sub(self.clone(), rhs)
417            }
418        }
419
420        impl Sub<&$name> for $name {
421            type Output = Self;
422
423            #[must_use]
424            #[inline]
425            fn sub(mut self, rhs: &Self) -> Self::Output {
426                SubAssign::sub_assign(&mut self, rhs);
427                self
428            }
429        }
430
431        impl Sub<$name> for &$name {
432            type Output = $name;
433
434            #[must_use]
435            #[inline]
436            fn sub(self, rhs: $name) -> Self::Output {
437                -Sub::sub(rhs, self)
438            }
439        }
440
441        impl SubAssign for $name {
442            #[inline]
443            fn sub_assign(&mut self, rhs: Self) {
444                SubAssign::sub_assign(self, &rhs)
445            }
446        }
447
448        impl Mul<&$name> for $name {
449            type Output = Self;
450
451            #[must_use]
452            #[inline]
453            fn mul(mut self, rhs: &Self) -> Self::Output {
454                MulAssign::mul_assign(&mut self, rhs);
455                self
456            }
457        }
458
459        impl<'a> Mul<&'a $name> for &'a $name {
460            type Output = $name;
461
462            #[must_use]
463            #[inline]
464            fn mul(self, rhs: Self) -> Self::Output {
465                Mul::mul(self.clone(), rhs)
466            }
467        }
468
469        impl Mul for $name {
470            type Output = Self;
471
472            #[must_use]
473            #[inline]
474            fn mul(mut self, rhs: Self) -> Self::Output {
475                MulAssign::mul_assign(&mut self, rhs);
476                self
477            }
478        }
479
480        impl MulAssign for $name {
481            #[inline]
482            fn mul_assign(&mut self, rhs: Self) {
483                MulAssign::mul_assign(self, &rhs);
484            }
485        }
486
487        impl Mul<$name> for &$name {
488            type Output = $name;
489
490            #[must_use]
491            #[inline]
492            fn mul(self, rhs: $name) -> Self::Output {
493                Mul::mul(rhs, self)
494            }
495        }
496
497        impl Div for $name {
498            type Output = Self;
499
500            #[must_use]
501            #[inline]
502            fn div(mut self, rhs: Self) -> Self::Output {
503                DivAssign::div_assign(&mut self, rhs);
504                self
505            }
506        }
507
508        impl Div<&$name> for $name {
509            type Output = Self;
510
511            #[must_use]
512            #[inline]
513            fn div(mut self, rhs: &Self) -> Self::Output {
514                DivAssign::div_assign(&mut self, rhs);
515                self
516            }
517        }
518
519        impl<'a> Div<&'a $name> for &'a $name {
520            type Output = $name;
521
522            #[must_use]
523            #[inline]
524            fn div(self, rhs: Self) -> Self::Output {
525                Div::div(self.clone(), rhs)
526            }
527        }
528
529        impl DivAssign for $name {
530            #[inline]
531            fn div_assign(&mut self, rhs: Self) {
532                DivAssign::div_assign(self, &rhs);
533            }
534        }
535    }
536}
537
538rational_forward!(Rational8);
539rational_forward!(Rational16);
540rational_forward!(Rational32);
541rational_forward!(Rational64);
542rational_forward!(Rational128);
543rational_forward!(RationalUsize);
544rational_forward!(NonZeroRational8);
545rational_forward!(NonZeroRational16);
546rational_forward!(NonZeroRational32);
547rational_forward!(NonZeroRational64);
548rational_forward!(NonZeroRational128);
549rational_forward!(NonZeroRationalUsize);