relp_num/rational/small/ops/
with_int.rs

1use std::cmp::Ordering;
2use std::num::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
3use std::num::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
4use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
5
6use num_traits::{One, Zero};
7
8use crate::{Rational128, Rational16, Rational32, Rational64, Rational8, RationalUsize};
9use crate::non_zero::NonZero;
10use crate::NonZeroSign;
11use crate::NonZeroSigned;
12use crate::rational::small::ops::building_blocks::{gcd128, gcd16, gcd32, gcd64, gcd8, gcd_usize};
13use crate::Sign;
14use crate::sign::Negateable;
15use crate::Signed;
16
17macro_rules! forwards {
18    ($ty:ty, $large:ty) => {
19        impl Add<$ty> for $large {
20            type Output = Self;
21
22            #[must_use]
23            #[inline]
24            fn add(mut self, rhs: $ty) -> Self::Output {
25                AddAssign::add_assign(&mut self, rhs);
26                self
27            }
28        }
29
30        impl Add<&$ty> for $large {
31            type Output = Self;
32
33            #[must_use]
34            #[inline]
35            fn add(mut self, rhs: &$ty) -> Self::Output {
36                AddAssign::add_assign(&mut self, rhs);
37                self
38            }
39        }
40
41        impl Add<$ty> for &$large {
42            type Output = $large;
43
44            #[must_use]
45            #[inline]
46            fn add(self, rhs: $ty) -> Self::Output {
47                Add::add(self.clone(), rhs)
48            }
49        }
50
51        impl Add<&$ty> for &$large {
52            type Output = $large;
53
54            #[must_use]
55            #[inline]
56            fn add(self, rhs: &$ty) -> Self::Output {
57                Add::add(self, *rhs)
58            }
59        }
60
61        impl AddAssign<&$ty> for $large {
62            #[inline]
63            fn add_assign(&mut self, rhs: &$ty) {
64                AddAssign::add_assign(self, *rhs);
65            }
66        }
67
68        impl Sub<$ty> for $large {
69            type Output = Self;
70
71            #[must_use]
72            #[inline]
73            fn sub(mut self, rhs: $ty) -> Self::Output {
74                SubAssign::sub_assign(&mut self, rhs);
75                self
76            }
77        }
78
79        impl Sub<&$ty> for $large {
80            type Output = Self;
81
82            #[must_use]
83            #[inline]
84            fn sub(mut self, rhs: &$ty) -> Self::Output {
85                SubAssign::sub_assign(&mut self, rhs);
86                self
87            }
88        }
89
90        impl Sub<$ty> for &$large {
91            type Output = $large;
92
93            #[must_use]
94            #[inline]
95            fn sub(self, rhs: $ty) -> Self::Output {
96                Sub::sub(self.clone(), rhs)
97            }
98        }
99
100        impl Sub<&$ty> for &$large {
101            type Output = $large;
102
103            #[must_use]
104            #[inline]
105            fn sub(self, rhs: &$ty) -> Self::Output {
106                Sub::sub(self, *rhs)
107            }
108        }
109
110        impl SubAssign<&$ty> for $large {
111            #[inline]
112            fn sub_assign(&mut self, rhs: &$ty) {
113                SubAssign::sub_assign(self, *rhs);
114            }
115        }
116
117        impl Mul<$ty> for $large {
118            type Output = Self;
119
120            #[must_use]
121            #[inline]
122            fn mul(mut self, rhs: $ty) -> Self::Output {
123                MulAssign::mul_assign(&mut self, rhs);
124                self
125            }
126        }
127
128        impl Mul<&$ty> for $large {
129            type Output = Self;
130
131            #[must_use]
132            #[inline]
133            fn mul(mut self, rhs: &$ty) -> Self::Output {
134                MulAssign::mul_assign(&mut self, rhs);
135                self
136            }
137        }
138
139        impl Mul<$ty> for &$large {
140            type Output = $large;
141
142            #[must_use]
143            #[inline]
144            fn mul(self, rhs: $ty) -> Self::Output {
145                Mul::mul(self.clone(), rhs)
146            }
147        }
148
149        impl Mul<&$ty> for &$large {
150            type Output = $large;
151
152            #[must_use]
153            #[inline]
154            fn mul(self, rhs: &$ty) -> Self::Output {
155                Mul::mul(self, *rhs)
156            }
157        }
158
159        impl MulAssign<&$ty> for $large {
160            #[inline]
161            fn mul_assign(&mut self, rhs: &$ty) {
162                MulAssign::mul_assign(self, *rhs);
163            }
164        }
165
166        impl Div<$ty> for $large {
167            type Output = Self;
168
169            #[must_use]
170            #[inline]
171            fn div(mut self, rhs: $ty) -> Self::Output {
172                DivAssign::div_assign(&mut self, rhs);
173                self
174            }
175        }
176
177        impl Div<&$ty> for $large {
178            type Output = Self;
179
180            #[must_use]
181            #[inline]
182            fn div(mut self, rhs: &$ty) -> Self::Output {
183                DivAssign::div_assign(&mut self, rhs);
184                self
185            }
186        }
187
188        impl Div<$ty> for &$large {
189            type Output = $large;
190
191            #[must_use]
192            #[inline]
193            fn div(self, rhs: $ty) -> Self::Output {
194                Div::div(self.clone(), rhs)
195            }
196        }
197
198        impl Div<&$ty> for &$large {
199            type Output = $large;
200
201            #[must_use]
202            #[inline]
203            fn div(self, rhs: &$ty) -> Self::Output {
204                Div::div(self, *rhs)
205            }
206        }
207
208        impl DivAssign<&$ty> for $large {
209            #[inline]
210            fn div_assign(&mut self, rhs: &$ty) {
211                DivAssign::div_assign(self, *rhs);
212            }
213        }
214
215        impl PartialEq<$large> for $ty {
216            #[inline]
217            fn eq(&self, rhs: &$large) -> bool {
218                PartialEq::eq(rhs, self)
219            }
220        }
221    }
222}
223
224forwards!(u8, Rational8);
225forwards!(NonZeroU8, Rational8);
226forwards!(i8, Rational8);
227forwards!(NonZeroI8, Rational8);
228
229forwards!(u8, Rational16);
230forwards!(u16, Rational16);
231forwards!(NonZeroU8, Rational16);
232forwards!(NonZeroU16, Rational16);
233forwards!(i8, Rational16);
234forwards!(i16, Rational16);
235forwards!(NonZeroI8, Rational16);
236forwards!(NonZeroI16, Rational16);
237
238forwards!(u8, Rational32);
239forwards!(u16, Rational32);
240forwards!(u32, Rational32);
241forwards!(NonZeroU8, Rational32);
242forwards!(NonZeroU16, Rational32);
243forwards!(NonZeroU32, Rational32);
244forwards!(i8, Rational32);
245forwards!(i16, Rational32);
246forwards!(i32, Rational32);
247forwards!(NonZeroI8, Rational32);
248forwards!(NonZeroI16, Rational32);
249forwards!(NonZeroI32, Rational32);
250
251forwards!(u8, Rational64);
252forwards!(u16, Rational64);
253forwards!(u32, Rational64);
254forwards!(u64, Rational64);
255forwards!(usize, Rational64);
256forwards!(NonZeroU8, Rational64);
257forwards!(NonZeroU16, Rational64);
258forwards!(NonZeroU32, Rational64);
259forwards!(NonZeroU64, Rational64);
260forwards!(NonZeroUsize, Rational64);
261forwards!(i8, Rational64);
262forwards!(i16, Rational64);
263forwards!(i32, Rational64);
264forwards!(i64, Rational64);
265forwards!(isize, Rational64);
266forwards!(NonZeroI8, Rational64);
267forwards!(NonZeroI16, Rational64);
268forwards!(NonZeroI32, Rational64);
269forwards!(NonZeroI64, Rational64);
270forwards!(NonZeroIsize, Rational64);
271
272forwards!(u8, Rational128);
273forwards!(u16, Rational128);
274forwards!(u32, Rational128);
275forwards!(u64, Rational128);
276forwards!(u128, Rational128);
277forwards!(usize, Rational128);
278forwards!(NonZeroU8, Rational128);
279forwards!(NonZeroU16, Rational128);
280forwards!(NonZeroU32, Rational128);
281forwards!(NonZeroU64, Rational128);
282forwards!(NonZeroU128, Rational128);
283forwards!(NonZeroUsize, Rational128);
284forwards!(i8, Rational128);
285forwards!(i16, Rational128);
286forwards!(i32, Rational128);
287forwards!(i64, Rational128);
288forwards!(i128, Rational128);
289forwards!(isize, Rational128);
290forwards!(NonZeroI8, Rational128);
291forwards!(NonZeroI16, Rational128);
292forwards!(NonZeroI32, Rational128);
293forwards!(NonZeroI64, Rational128);
294forwards!(NonZeroI128, Rational128);
295forwards!(NonZeroIsize, Rational128);
296
297macro_rules! impls {
298    ($name:ident, $large: ty, $ty:ty, $nzty:ty, $sty:ty, $nzsty:ty, $mul_name:ident, $gcd_name:ident) => {
299        impl AddAssign<$ty> for $name {
300            #[inline]
301            fn add_assign(&mut self, rhs: $ty) {
302                self.add_assign(rhs as $large);
303            }
304        }
305
306        impl AddAssign<$nzty> for $name {
307            #[inline]
308            fn add_assign(&mut self, rhs: $nzty) {
309                self.add_assign(rhs.get() as $large);
310            }
311        }
312
313        impl AddAssign<$sty> for $name {
314            #[inline]
315            fn add_assign(&mut self, rhs: $sty) {
316                let unsigned = rhs.unsigned_abs() as $large;
317                match Signed::signum(&rhs) {
318                    Sign::Positive => self.add_assign(unsigned),
319                    Sign::Zero => (),
320                    Sign::Negative => self.sub_assign(unsigned),
321                }
322            }
323        }
324
325        impl AddAssign<$nzsty> for $name {
326            #[inline]
327            fn add_assign(&mut self, rhs: $nzsty) {
328                let unsigned = rhs.get().unsigned_abs() as $large;
329                match NonZeroSigned::non_zero_signum(&rhs) {
330                    NonZeroSign::Positive => self.add_assign(unsigned),
331                    NonZeroSign::Negative => self.sub_assign(unsigned),
332                }
333            }
334        }
335
336        impl SubAssign<$ty> for $name {
337            #[inline]
338            fn sub_assign(&mut self, rhs: $ty) {
339                self.sub_assign(rhs as $large);
340            }
341        }
342
343        impl SubAssign<$nzty> for $name {
344            #[inline]
345            fn sub_assign(&mut self, rhs: $nzty) {
346                self.sub_assign(rhs.get() as $large);
347            }
348        }
349
350        impl SubAssign<$sty> for $name {
351            #[inline]
352            fn sub_assign(&mut self, rhs: $sty) {
353                let unsigned = rhs.unsigned_abs() as $large;
354                match Signed::signum(&rhs) {
355                    Sign::Positive => self.sub_assign(unsigned),
356                    Sign::Zero => (),
357                    Sign::Negative => self.add_assign(unsigned),
358                }
359            }
360        }
361
362        impl SubAssign<$nzsty> for $name {
363            #[inline]
364            fn sub_assign(&mut self, rhs: $nzsty) {
365                let unsigned = rhs.get().unsigned_abs() as $large;
366                match NonZeroSigned::non_zero_signum(&rhs) {
367                    NonZeroSign::Positive => self.sub_assign(unsigned),
368                    NonZeroSign::Negative => self.add_assign(unsigned),
369                }
370            }
371        }
372
373        impl MulAssign<$ty> for $name {
374            #[inline]
375            fn mul_assign(&mut self, rhs: $ty) {
376                if rhs.is_not_zero() {
377                    $mul_name(&mut self.numerator, &mut self.denominator, rhs as $large);
378                } else {
379                    self.set_zero();
380                }
381            }
382        }
383
384        impl MulAssign<$nzty> for $name {
385            #[inline]
386            fn mul_assign(&mut self, rhs: $nzty) {
387                $mul_name(&mut self.numerator, &mut self.denominator, rhs.get() as $large);
388            }
389        }
390
391        impl MulAssign<$sty> for $name {
392            #[inline]
393            fn mul_assign(&mut self, rhs: $sty) {
394                if rhs.is_not_zero() {
395                    $mul_name(&mut self.numerator, &mut self.denominator, rhs.unsigned_abs() as $large);
396
397                    if rhs.is_negative() {
398                        self.negate();
399                    }
400                } else {
401                    self.set_zero();
402                }
403            }
404        }
405
406        impl MulAssign<$nzsty> for $name {
407            #[inline]
408            fn mul_assign(&mut self, rhs: $nzsty) {
409                $mul_name(&mut self.numerator, &mut self.denominator, rhs.get().unsigned_abs() as $large);
410
411                if rhs.is_negative() {
412                    self.negate();
413                }
414            }
415        }
416
417        impl DivAssign<$ty> for $name {
418            #[inline]
419            fn div_assign(&mut self, rhs: $ty) {
420                if rhs.is_not_zero() {
421                    match self.sign {
422                        Sign::Positive | Sign::Negative => {
423                            $mul_name(&mut self.denominator, &mut self.numerator, rhs as $large);
424                        }
425                        Sign::Zero => {}
426                    }
427                } else {
428                    panic!("attempt to divide by zero");
429                }
430            }
431        }
432
433        impl DivAssign<$nzty> for $name {
434            #[inline]
435            fn div_assign(&mut self, rhs: $nzty) {
436                match self.sign {
437                    Sign::Positive | Sign::Negative => {
438                        $mul_name(&mut self.denominator, &mut self.numerator, rhs.get() as $large);
439                    }
440                    Sign::Zero => {}
441                }
442            }
443        }
444
445        impl DivAssign<$sty> for $name {
446            #[inline]
447            fn div_assign(&mut self, rhs: $sty) {
448                if rhs.is_not_zero() {
449                    match self.sign {
450                        Sign::Positive | Sign::Negative => {
451                            $mul_name(&mut self.denominator, &mut self.numerator, rhs.unsigned_abs() as $large);
452                        }
453                        Sign::Zero => {}
454                    }
455
456                    if rhs.is_negative() {
457                        self.negate();
458                    }
459                } else {
460                    panic!("attempt to divide by zero");
461                }
462            }
463        }
464
465        impl DivAssign<$nzsty> for $name {
466            #[inline]
467            fn div_assign(&mut self, rhs: $nzsty) {
468                match self.sign {
469                    Sign::Positive | Sign::Negative => {
470                        $mul_name(&mut self.denominator, &mut self.numerator, rhs.get().unsigned_abs() as $large);
471                    }
472                    Sign::Zero => {}
473                }
474
475                if rhs.is_negative() {
476                    self.negate();
477                }
478            }
479        }
480
481        impl PartialEq<$ty> for $name {
482            #[inline]
483            fn eq(&self, rhs: &$ty) -> bool {
484                self.numerator == *rhs as $large && self.denominator.is_one() && self.sign == Sign::Positive
485            }
486        }
487
488        impl PartialEq<$nzty> for $name {
489            #[inline]
490            fn eq(&self, rhs: &$nzty) -> bool {
491                self.numerator == rhs.get() as $large && self.denominator.is_one() && self.sign == Sign::Positive
492            }
493        }
494
495        impl PartialEq<$sty> for $name {
496            #[inline]
497            fn eq(&self, rhs: &$sty) -> bool {
498                self.numerator == rhs.unsigned_abs() as $large && self.denominator.is_one() && self.sign == Signed::signum(rhs)
499            }
500        }
501
502        impl PartialEq<$nzsty> for $name {
503            #[inline]
504            fn eq(&self, rhs: &$nzsty) -> bool {
505                self.numerator == rhs.get().unsigned_abs() as $large && self.denominator.is_one() && self.sign == Signed::signum(rhs)
506            }
507        }
508    }
509}
510
511impls!(Rational8, u8, u8, NonZeroU8, i8, NonZeroI8, mul8, gcd8);
512
513impls!(Rational16, u16, u8, NonZeroU8, i8, NonZeroI8, mul16, gcd16);
514impls!(Rational16, u16, u16, NonZeroU16, i16, NonZeroI16, mul16, gcd16);
515
516impls!(Rational32, u32, u8, NonZeroU8, i8, NonZeroI8, mul32, gcd32);
517impls!(Rational32, u32, u16, NonZeroU16, i16, NonZeroI16, mul32, gcd32);
518impls!(Rational32, u32, u32, NonZeroU32, i32, NonZeroI32, mul32, gcd32);
519
520impls!(Rational64, u64, u8, NonZeroU8, i8, NonZeroI8, mul64, gcd64);
521impls!(Rational64, u64, u16, NonZeroU16, i16, NonZeroI16, mul64, gcd64);
522impls!(Rational64, u64, u32, NonZeroU32, i32, NonZeroI32, mul64, gcd64);
523impls!(Rational64, u64, u64, NonZeroU64, i64, NonZeroI64, mul64, gcd64);
524impls!(Rational64, u64, usize, NonZeroUsize, isize, NonZeroIsize, mul64, gcd64);
525
526impls!(Rational128, u128, u8, NonZeroU8, i8, NonZeroI8, mul128, gcd128);
527impls!(Rational128, u128, u16, NonZeroU16, i16, NonZeroI16, mul128, gcd128);
528impls!(Rational128, u128, u32, NonZeroU32, i32, NonZeroI32, mul128, gcd128);
529impls!(Rational128, u128, u64, NonZeroU64, i64, NonZeroI64, mul128, gcd128);
530impls!(Rational128, u128, usize, NonZeroUsize, isize, NonZeroIsize, mul128, gcd128);
531impls!(Rational128, u128, u128, NonZeroU128, i128, NonZeroI128, mul128, gcd128);
532
533impls!(RationalUsize, usize, u8, NonZeroU8, i8, NonZeroI8, mul_usize, gcd_usize);
534impls!(RationalUsize, usize, u16, NonZeroU16, i16, NonZeroI16, mul_usize, gcd_usize);
535impls!(RationalUsize, usize, u32, NonZeroU32, i32, NonZeroI32, mul_usize, gcd_usize);
536impls!(RationalUsize, usize, u64, NonZeroU64, i64, NonZeroI64, mul_usize, gcd_usize);
537impls!(RationalUsize, usize, usize, NonZeroUsize, isize, NonZeroIsize, mul_usize, gcd_usize);
538
539macro_rules! shared {
540    ($ty:ty, $large:ty, $mul_name:ident, $gcd_name:ident) => {
541        impl $ty {
542            #[inline]
543            fn add_assign(&mut self, rhs: $large) {
544                match self.signum() {
545                    Sign::Positive => self.numerator += rhs * self.denominator,
546                    Sign::Zero => {
547                        self.numerator = rhs as $large;
548                        debug_assert!(self.denominator.is_one());
549                    }
550                    Sign::Negative => {
551                        let difference = rhs * self.denominator;
552                        match self.numerator.cmp(&difference) {
553                            Ordering::Less => {
554                                self.numerator = difference - self.numerator;
555                                self.sign = Sign::Positive;
556                            }
557                            Ordering::Equal => self.set_zero(),
558                            Ordering::Greater => self.numerator -= difference,
559                        }
560                    }
561                }
562            }
563            #[inline]
564            fn sub_assign(&mut self, rhs: $large) {
565                match self.signum() {
566                    Sign::Positive => {
567                        let difference = rhs * self.denominator;
568                        match self.numerator.cmp(&difference) {
569                            Ordering::Less => {
570                                self.numerator = difference - self.numerator;
571                                self.sign = Sign::Negative;
572                            }
573                            Ordering::Equal => self.set_zero(),
574                            Ordering::Greater => self.numerator -= difference,
575                        }
576                    },
577                    Sign::Zero => {
578                        self.numerator = rhs as $large;
579                        debug_assert!(self.denominator.is_one());
580                        self.sign = Sign::Negative;
581                    }
582                    Sign::Negative => self.numerator += rhs * self.denominator,
583                }
584            }
585        }
586
587        #[inline]
588        fn $mul_name(left_numerator: &mut $large, left_denominator: &mut $large, right: $large) {
589            debug_assert_ne!(right, 0);
590
591            if right != 1 {
592                if *left_denominator != 1 {
593                    let gcd = $gcd_name(*left_denominator, right);
594                    *left_numerator *= right / gcd;
595                    *left_denominator /= gcd;
596                } else {
597                    *left_numerator *= right;
598                }
599            }
600        }
601    }
602}
603
604shared!(Rational8, u8, mul8, gcd8);
605shared!(Rational16, u16, mul16, gcd16);
606shared!(Rational32, u32, mul32, gcd32);
607shared!(Rational64, u64, mul64, gcd64);
608shared!(Rational128, u128, mul128, gcd128);
609shared!(RationalUsize, usize, mul_usize, gcd_usize);
610
611#[cfg(test)]
612mod test {
613    use crate::{R16, R32, R64};
614    
615    #[test]
616    fn test_add() {
617        assert_eq!(R64!(2, 3) + 2, R64!(8, 3));
618        assert_eq!(R64!(5, 6) + 7, R64!(7 * 6 + 5, 6));
619        assert_eq!(R64!(5, 6) - 7, R64!(-7 * 6 + 5, 6));
620        assert_eq!(R64!(5, 6) + (-7) as i32, R64!(-7 * 6 + 5, 6));
621        assert_eq!(R64!(-5, 6) + 7, R64!(7 * 6 - 5, 6));
622        assert_eq!(R64!(-5, 6) + (-7), -R64!(7 * 6 + 5, 6));
623        assert_eq!(R64!(-2, 3) + 2, R64!(4, 3));
624        assert_eq!(R64!(2, 3) + 0, R64!(2, 3));
625        assert_eq!(R64!(2, 3) - 2, R64!(-4, 3));
626        assert_eq!(R64!(0) - 1, R64!(-1));
627        assert_eq!(R64!(-2, 3) - 2, R64!(-8, 3));
628    }
629
630    #[test]
631    fn test_mul() {
632        let mut x = R16!(1);
633        x /= &19_u16;
634        assert_eq!(x, R16!(1, 19));
635
636        assert_eq!(R16!(1) / &19_u16, R16!(1, 19));
637        assert_eq!(R16!(1) * &19_u16, R16!(19));
638        assert_eq!(R32!(3) * &19, R32!(19 * 3));
639        assert_eq!(R32!(3) / &19, R32!(3, 19));
640        assert_eq!(R32!(3) * &6, R32!(3 * 6));
641        assert_eq!(R32!(3) / &6, R32!(3, 6));
642        assert_eq!(R32!(3) / &(-6), R32!(-3, 6));
643        assert_eq!(R32!(3) * 0, R32!(0));
644        assert_eq!(R32!(3) / &6, R32!(3, 6));
645    }
646
647    #[test]
648    #[should_panic]
649    #[allow(unused_must_use)]
650    fn test_div_by_zero() {
651        R32!(3) / &0;
652    }
653}