Skip to main content

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            #[inline]
23            fn add(mut self, rhs: $ty) -> Self::Output {
24                AddAssign::add_assign(&mut self, rhs);
25                self
26            }
27        }
28
29        impl Add<&$ty> for $large {
30            type Output = Self;
31
32            #[inline]
33            fn add(mut self, rhs: &$ty) -> Self::Output {
34                AddAssign::add_assign(&mut self, rhs);
35                self
36            }
37        }
38
39        impl Add<$ty> for &$large {
40            type Output = $large;
41
42            #[inline]
43            fn add(self, rhs: $ty) -> Self::Output {
44                Add::add(self.clone(), rhs)
45            }
46        }
47
48        impl Add<&$ty> for &$large {
49            type Output = $large;
50
51            #[inline]
52            fn add(self, rhs: &$ty) -> Self::Output {
53                Add::add(self, *rhs)
54            }
55        }
56
57        impl AddAssign<&$ty> for $large {
58            #[inline]
59            fn add_assign(&mut self, rhs: &$ty) {
60                AddAssign::add_assign(self, *rhs);
61            }
62        }
63
64        impl Sub<$ty> for $large {
65            type Output = Self;
66
67            #[inline]
68            fn sub(mut self, rhs: $ty) -> Self::Output {
69                SubAssign::sub_assign(&mut self, rhs);
70                self
71            }
72        }
73
74        impl Sub<&$ty> for $large {
75            type Output = Self;
76
77            #[inline]
78            fn sub(mut self, rhs: &$ty) -> Self::Output {
79                SubAssign::sub_assign(&mut self, rhs);
80                self
81            }
82        }
83
84        impl Sub<$ty> for &$large {
85            type Output = $large;
86
87            #[inline]
88            fn sub(self, rhs: $ty) -> Self::Output {
89                Sub::sub(self.clone(), rhs)
90            }
91        }
92
93        impl Sub<&$ty> for &$large {
94            type Output = $large;
95
96            #[inline]
97            fn sub(self, rhs: &$ty) -> Self::Output {
98                Sub::sub(self, *rhs)
99            }
100        }
101
102        impl SubAssign<&$ty> for $large {
103            #[inline]
104            fn sub_assign(&mut self, rhs: &$ty) {
105                SubAssign::sub_assign(self, *rhs);
106            }
107        }
108
109        impl Mul<$ty> for $large {
110            type Output = Self;
111
112            #[inline]
113            fn mul(mut self, rhs: $ty) -> Self::Output {
114                MulAssign::mul_assign(&mut self, rhs);
115                self
116            }
117        }
118
119        impl Mul<&$ty> for $large {
120            type Output = Self;
121
122            #[inline]
123            fn mul(mut self, rhs: &$ty) -> Self::Output {
124                MulAssign::mul_assign(&mut self, rhs);
125                self
126            }
127        }
128
129        impl Mul<$ty> for &$large {
130            type Output = $large;
131
132            #[inline]
133            fn mul(self, rhs: $ty) -> Self::Output {
134                Mul::mul(self.clone(), rhs)
135            }
136        }
137
138        impl Mul<&$ty> for &$large {
139            type Output = $large;
140
141            #[inline]
142            fn mul(self, rhs: &$ty) -> Self::Output {
143                Mul::mul(self, *rhs)
144            }
145        }
146
147        impl MulAssign<&$ty> for $large {
148            #[inline]
149            fn mul_assign(&mut self, rhs: &$ty) {
150                MulAssign::mul_assign(self, *rhs);
151            }
152        }
153
154        impl Div<$ty> for $large {
155            type Output = Self;
156
157            #[inline]
158            fn div(mut self, rhs: $ty) -> Self::Output {
159                DivAssign::div_assign(&mut self, rhs);
160                self
161            }
162        }
163
164        impl Div<&$ty> for $large {
165            type Output = Self;
166
167            #[inline]
168            fn div(mut self, rhs: &$ty) -> Self::Output {
169                DivAssign::div_assign(&mut self, rhs);
170                self
171            }
172        }
173
174        impl Div<$ty> for &$large {
175            type Output = $large;
176
177            #[inline]
178            fn div(self, rhs: $ty) -> Self::Output {
179                Div::div(self.clone(), rhs)
180            }
181        }
182
183        impl Div<&$ty> for &$large {
184            type Output = $large;
185
186            #[inline]
187            fn div(self, rhs: &$ty) -> Self::Output {
188                Div::div(self, *rhs)
189            }
190        }
191
192        impl DivAssign<&$ty> for $large {
193            #[inline]
194            fn div_assign(&mut self, rhs: &$ty) {
195                DivAssign::div_assign(self, *rhs);
196            }
197        }
198
199        impl PartialEq<$large> for $ty {
200            #[inline]
201            fn eq(&self, rhs: &$large) -> bool {
202                PartialEq::eq(rhs, self)
203            }
204        }
205    }
206}
207
208forwards!(u8, Rational8);
209forwards!(NonZeroU8, Rational8);
210forwards!(i8, Rational8);
211forwards!(NonZeroI8, Rational8);
212
213forwards!(u8, Rational16);
214forwards!(u16, Rational16);
215forwards!(NonZeroU8, Rational16);
216forwards!(NonZeroU16, Rational16);
217forwards!(i8, Rational16);
218forwards!(i16, Rational16);
219forwards!(NonZeroI8, Rational16);
220forwards!(NonZeroI16, Rational16);
221
222forwards!(u8, Rational32);
223forwards!(u16, Rational32);
224forwards!(u32, Rational32);
225forwards!(NonZeroU8, Rational32);
226forwards!(NonZeroU16, Rational32);
227forwards!(NonZeroU32, Rational32);
228forwards!(i8, Rational32);
229forwards!(i16, Rational32);
230forwards!(i32, Rational32);
231forwards!(NonZeroI8, Rational32);
232forwards!(NonZeroI16, Rational32);
233forwards!(NonZeroI32, Rational32);
234
235forwards!(u8, Rational64);
236forwards!(u16, Rational64);
237forwards!(u32, Rational64);
238forwards!(u64, Rational64);
239forwards!(usize, Rational64);
240forwards!(NonZeroU8, Rational64);
241forwards!(NonZeroU16, Rational64);
242forwards!(NonZeroU32, Rational64);
243forwards!(NonZeroU64, Rational64);
244forwards!(NonZeroUsize, Rational64);
245forwards!(i8, Rational64);
246forwards!(i16, Rational64);
247forwards!(i32, Rational64);
248forwards!(i64, Rational64);
249forwards!(isize, Rational64);
250forwards!(NonZeroI8, Rational64);
251forwards!(NonZeroI16, Rational64);
252forwards!(NonZeroI32, Rational64);
253forwards!(NonZeroI64, Rational64);
254forwards!(NonZeroIsize, Rational64);
255
256forwards!(u8, Rational128);
257forwards!(u16, Rational128);
258forwards!(u32, Rational128);
259forwards!(u64, Rational128);
260forwards!(u128, Rational128);
261forwards!(usize, Rational128);
262forwards!(NonZeroU8, Rational128);
263forwards!(NonZeroU16, Rational128);
264forwards!(NonZeroU32, Rational128);
265forwards!(NonZeroU64, Rational128);
266forwards!(NonZeroU128, Rational128);
267forwards!(NonZeroUsize, Rational128);
268forwards!(i8, Rational128);
269forwards!(i16, Rational128);
270forwards!(i32, Rational128);
271forwards!(i64, Rational128);
272forwards!(i128, Rational128);
273forwards!(isize, Rational128);
274forwards!(NonZeroI8, Rational128);
275forwards!(NonZeroI16, Rational128);
276forwards!(NonZeroI32, Rational128);
277forwards!(NonZeroI64, Rational128);
278forwards!(NonZeroI128, Rational128);
279forwards!(NonZeroIsize, Rational128);
280
281macro_rules! impls {
282    ($name:ident, $large: ty, $ty:ty, $nzty:ty, $sty:ty, $nzsty:ty, $mul_name:ident, $gcd_name:ident) => {
283        impl AddAssign<$ty> for $name {
284            #[inline]
285            fn add_assign(&mut self, rhs: $ty) {
286                // The inherent method assumes a non zero right hand side: a zero would be given a
287                // sign, breaking the invariant that only a zero numerator has sign `Sign::Zero`.
288                if rhs.is_not_zero() {
289                    self.add_assign(rhs as $large);
290                }
291            }
292        }
293
294        impl AddAssign<$nzty> for $name {
295            #[inline]
296            fn add_assign(&mut self, rhs: $nzty) {
297                self.add_assign(rhs.get() as $large);
298            }
299        }
300
301        impl AddAssign<$sty> for $name {
302            #[inline]
303            fn add_assign(&mut self, rhs: $sty) {
304                let unsigned = rhs.unsigned_abs() as $large;
305                match Signed::signum(&rhs) {
306                    Sign::Positive => self.add_assign(unsigned),
307                    Sign::Zero => (),
308                    Sign::Negative => self.sub_assign(unsigned),
309                }
310            }
311        }
312
313        impl AddAssign<$nzsty> for $name {
314            #[inline]
315            fn add_assign(&mut self, rhs: $nzsty) {
316                let unsigned = rhs.get().unsigned_abs() as $large;
317                match NonZeroSigned::non_zero_signum(&rhs) {
318                    NonZeroSign::Positive => self.add_assign(unsigned),
319                    NonZeroSign::Negative => self.sub_assign(unsigned),
320                }
321            }
322        }
323
324        impl SubAssign<$ty> for $name {
325            #[inline]
326            fn sub_assign(&mut self, rhs: $ty) {
327                // The inherent method assumes a non zero right hand side: a zero would be given a
328                // sign, breaking the invariant that only a zero numerator has sign `Sign::Zero`.
329                if rhs.is_not_zero() {
330                    self.sub_assign(rhs as $large);
331                }
332            }
333        }
334
335        impl SubAssign<$nzty> for $name {
336            #[inline]
337            fn sub_assign(&mut self, rhs: $nzty) {
338                self.sub_assign(rhs.get() as $large);
339            }
340        }
341
342        impl SubAssign<$sty> for $name {
343            #[inline]
344            fn sub_assign(&mut self, rhs: $sty) {
345                let unsigned = rhs.unsigned_abs() as $large;
346                match Signed::signum(&rhs) {
347                    Sign::Positive => self.sub_assign(unsigned),
348                    Sign::Zero => (),
349                    Sign::Negative => self.add_assign(unsigned),
350                }
351            }
352        }
353
354        impl SubAssign<$nzsty> for $name {
355            #[inline]
356            fn sub_assign(&mut self, rhs: $nzsty) {
357                let unsigned = rhs.get().unsigned_abs() as $large;
358                match NonZeroSigned::non_zero_signum(&rhs) {
359                    NonZeroSign::Positive => self.sub_assign(unsigned),
360                    NonZeroSign::Negative => self.add_assign(unsigned),
361                }
362            }
363        }
364
365        impl MulAssign<$ty> for $name {
366            #[inline]
367            fn mul_assign(&mut self, rhs: $ty) {
368                if rhs.is_not_zero() {
369                    $mul_name(&mut self.numerator, &mut self.denominator, rhs as $large);
370                } else {
371                    self.set_zero();
372                }
373            }
374        }
375
376        impl MulAssign<$nzty> for $name {
377            #[inline]
378            fn mul_assign(&mut self, rhs: $nzty) {
379                $mul_name(&mut self.numerator, &mut self.denominator, rhs.get() as $large);
380            }
381        }
382
383        impl MulAssign<$sty> for $name {
384            #[inline]
385            fn mul_assign(&mut self, rhs: $sty) {
386                if rhs.is_not_zero() {
387                    $mul_name(&mut self.numerator, &mut self.denominator, rhs.unsigned_abs() as $large);
388
389                    if rhs.is_negative() {
390                        self.negate();
391                    }
392                } else {
393                    self.set_zero();
394                }
395            }
396        }
397
398        impl MulAssign<$nzsty> for $name {
399            #[inline]
400            fn mul_assign(&mut self, rhs: $nzsty) {
401                $mul_name(&mut self.numerator, &mut self.denominator, rhs.get().unsigned_abs() as $large);
402
403                if rhs.is_negative() {
404                    self.negate();
405                }
406            }
407        }
408
409        impl DivAssign<$ty> for $name {
410            #[inline]
411            fn div_assign(&mut self, rhs: $ty) {
412                if rhs.is_not_zero() {
413                    match self.sign {
414                        Sign::Positive | Sign::Negative => {
415                            $mul_name(&mut self.denominator, &mut self.numerator, rhs as $large);
416                        }
417                        Sign::Zero => {}
418                    }
419                } else {
420                    panic!("attempt to divide by zero");
421                }
422            }
423        }
424
425        impl DivAssign<$nzty> for $name {
426            #[inline]
427            fn div_assign(&mut self, rhs: $nzty) {
428                match self.sign {
429                    Sign::Positive | Sign::Negative => {
430                        $mul_name(&mut self.denominator, &mut self.numerator, rhs.get() as $large);
431                    }
432                    Sign::Zero => {}
433                }
434            }
435        }
436
437        impl DivAssign<$sty> for $name {
438            #[inline]
439            fn div_assign(&mut self, rhs: $sty) {
440                if rhs.is_not_zero() {
441                    match self.sign {
442                        Sign::Positive | Sign::Negative => {
443                            $mul_name(&mut self.denominator, &mut self.numerator, rhs.unsigned_abs() as $large);
444                        }
445                        Sign::Zero => {}
446                    }
447
448                    if rhs.is_negative() {
449                        self.negate();
450                    }
451                } else {
452                    panic!("attempt to divide by zero");
453                }
454            }
455        }
456
457        impl DivAssign<$nzsty> for $name {
458            #[inline]
459            fn div_assign(&mut self, rhs: $nzsty) {
460                match self.sign {
461                    Sign::Positive | Sign::Negative => {
462                        $mul_name(&mut self.denominator, &mut self.numerator, rhs.get().unsigned_abs() as $large);
463                    }
464                    Sign::Zero => {}
465                }
466
467                if rhs.is_negative() {
468                    self.negate();
469                }
470            }
471        }
472
473        impl PartialEq<$ty> for $name {
474            #[inline]
475            fn eq(&self, rhs: &$ty) -> bool {
476                // A zero has sign `Sign::Zero`, not `Sign::Positive`, so the sign of the right hand
477                // side has to be compared rather than assumed.
478                self.numerator == *rhs as $large && self.denominator.is_one() && self.sign == Signed::signum(rhs)
479            }
480        }
481
482        impl PartialEq<$nzty> for $name {
483            #[inline]
484            fn eq(&self, rhs: &$nzty) -> bool {
485                self.numerator == rhs.get() as $large && self.denominator.is_one() && self.sign == Signed::signum(rhs)
486            }
487        }
488
489        impl PartialEq<$sty> for $name {
490            #[inline]
491            fn eq(&self, rhs: &$sty) -> bool {
492                self.numerator == rhs.unsigned_abs() as $large && self.denominator.is_one() && self.sign == Signed::signum(rhs)
493            }
494        }
495
496        impl PartialEq<$nzsty> for $name {
497            #[inline]
498            fn eq(&self, rhs: &$nzsty) -> bool {
499                self.numerator == rhs.get().unsigned_abs() as $large && self.denominator.is_one() && self.sign == Signed::signum(rhs)
500            }
501        }
502    }
503}
504
505impls!(Rational8, u8, u8, NonZeroU8, i8, NonZeroI8, mul8, gcd8);
506
507impls!(Rational16, u16, u8, NonZeroU8, i8, NonZeroI8, mul16, gcd16);
508impls!(Rational16, u16, u16, NonZeroU16, i16, NonZeroI16, mul16, gcd16);
509
510impls!(Rational32, u32, u8, NonZeroU8, i8, NonZeroI8, mul32, gcd32);
511impls!(Rational32, u32, u16, NonZeroU16, i16, NonZeroI16, mul32, gcd32);
512impls!(Rational32, u32, u32, NonZeroU32, i32, NonZeroI32, mul32, gcd32);
513
514impls!(Rational64, u64, u8, NonZeroU8, i8, NonZeroI8, mul64, gcd64);
515impls!(Rational64, u64, u16, NonZeroU16, i16, NonZeroI16, mul64, gcd64);
516impls!(Rational64, u64, u32, NonZeroU32, i32, NonZeroI32, mul64, gcd64);
517impls!(Rational64, u64, u64, NonZeroU64, i64, NonZeroI64, mul64, gcd64);
518impls!(Rational64, u64, usize, NonZeroUsize, isize, NonZeroIsize, mul64, gcd64);
519
520impls!(Rational128, u128, u8, NonZeroU8, i8, NonZeroI8, mul128, gcd128);
521impls!(Rational128, u128, u16, NonZeroU16, i16, NonZeroI16, mul128, gcd128);
522impls!(Rational128, u128, u32, NonZeroU32, i32, NonZeroI32, mul128, gcd128);
523impls!(Rational128, u128, u64, NonZeroU64, i64, NonZeroI64, mul128, gcd128);
524impls!(Rational128, u128, usize, NonZeroUsize, isize, NonZeroIsize, mul128, gcd128);
525impls!(Rational128, u128, u128, NonZeroU128, i128, NonZeroI128, mul128, gcd128);
526
527impls!(RationalUsize, usize, u8, NonZeroU8, i8, NonZeroI8, mul_usize, gcd_usize);
528impls!(RationalUsize, usize, u16, NonZeroU16, i16, NonZeroI16, mul_usize, gcd_usize);
529impls!(RationalUsize, usize, u32, NonZeroU32, i32, NonZeroI32, mul_usize, gcd_usize);
530impls!(RationalUsize, usize, u64, NonZeroU64, i64, NonZeroI64, mul_usize, gcd_usize);
531impls!(RationalUsize, usize, usize, NonZeroUsize, isize, NonZeroIsize, mul_usize, gcd_usize);
532
533macro_rules! shared {
534    ($ty:ty, $large:ty, $wide:ty, $mul_name:ident, $gcd_name:ident) => {
535        impl $ty {
536            /// Add a non zero integer.
537            ///
538            /// The caller guarantees that `rhs` is not zero, because a zero would be given a sign
539            /// in the `Sign::Zero` arm.
540            #[inline]
541            fn add_assign(&mut self, rhs: $large) {
542                match self.signum() {
543                    Sign::Positive => self.numerator += rhs * self.denominator,
544                    Sign::Zero => {
545                        self.numerator = rhs;
546                        self.sign = Sign::Positive;
547                        debug_assert!(self.denominator.is_one());
548                    }
549                    Sign::Negative => self.sub_assign_magnitude(rhs),
550                }
551            }
552            /// Subtract a non zero integer.
553            ///
554            /// The caller guarantees that `rhs` is not zero, because a zero would be given a sign
555            /// in the `Sign::Zero` arm.
556            #[inline]
557            fn sub_assign(&mut self, rhs: $large) {
558                match self.signum() {
559                    Sign::Positive => self.sub_assign_magnitude(rhs),
560                    Sign::Zero => {
561                        self.numerator = rhs;
562                        self.sign = Sign::Negative;
563                        debug_assert!(self.denominator.is_one());
564                    }
565                    Sign::Negative => self.numerator += rhs * self.denominator,
566                }
567            }
568            /// Subtract the integer `rhs` from the magnitude of a non zero `self`.
569            ///
570            /// The sign is negated when `rhs` is the larger of the two, that is, when the value
571            /// moves past zero.
572            ///
573            /// The product `rhs * denominator` is computed in a wider type where one exists, so
574            /// that a product too large for the numerator still compares correctly, and so that a
575            /// result which does fit is exact. Only for the widest type can the product itself
576            /// overflow, and such a product is by definition larger than any representable
577            /// numerator, which is enough to get the sign right. The magnitude can then not be
578            /// represented; debug builds panic on the assertions, release builds truncate.
579            #[inline]
580            fn sub_assign_magnitude(&mut self, rhs: $large) {
581                let product = (rhs as $wide).checked_mul(self.denominator as $wide);
582                debug_assert!(product.is_some(), "attempt to multiply with overflow");
583
584                match product {
585                    Some(product) => {
586                        let numerator = self.numerator as $wide;
587                        match numerator.cmp(&product) {
588                            Ordering::Less => {
589                                let difference = product - numerator;
590                                debug_assert!(
591                                    difference <= <$large>::MAX as $wide,
592                                    "attempt to subtract with overflow",
593                                );
594                                self.numerator = difference as $large;
595                                self.sign.negate();
596                            }
597                            Ordering::Equal => self.set_zero(),
598                            // Smaller than the numerator, so it fits.
599                            Ordering::Greater => self.numerator -= product as $large,
600                        }
601                    }
602                    None => {
603                        self.numerator = rhs.wrapping_mul(self.denominator)
604                            .wrapping_sub(self.numerator);
605                        self.sign.negate();
606                    }
607                }
608            }
609        }
610
611        #[inline]
612        fn $mul_name(left_numerator: &mut $large, left_denominator: &mut $large, right: $large) {
613            debug_assert_ne!(right, 0);
614
615            if right != 1 {
616                if *left_denominator != 1 {
617                    let gcd = $gcd_name(*left_denominator, right);
618                    *left_numerator *= right / gcd;
619                    *left_denominator /= gcd;
620                } else {
621                    *left_numerator *= right;
622                }
623            }
624        }
625    }
626}
627
628// The third type is the one the intermediate products are computed in. It is twice as wide as the
629// second, except for the widest type, which has nothing to widen into.
630shared!(Rational8, u8, u16, mul8, gcd8);
631shared!(Rational16, u16, u32, mul16, gcd16);
632shared!(Rational32, u32, u64, mul32, gcd32);
633shared!(Rational64, u64, u128, mul64, gcd64);
634shared!(Rational128, u128, u128, mul128, gcd128);
635shared!(RationalUsize, usize, u128, mul_usize, gcd_usize);
636
637#[cfg(test)]
638mod test {
639    use std::num::NonZeroU32;
640
641    use num_traits::Zero;
642
643    use crate::{NonZero, Rational16, Rational8, Sign, Signed};
644    use crate::{R16, R32, R64};
645
646    #[test]
647    fn test_add() {
648        assert_eq!(R64!(2, 3) + 2, R64!(8, 3));
649        assert_eq!(R64!(5, 6) + 7, R64!(7 * 6 + 5, 6));
650        assert_eq!(R64!(5, 6) - 7, R64!(-7 * 6 + 5, 6));
651        assert_eq!(R64!(5, 6) + -7_i32, R64!(-7 * 6 + 5, 6));
652        assert_eq!(R64!(-5, 6) + 7, R64!(7 * 6 - 5, 6));
653        assert_eq!(R64!(-5, 6) + (-7), -R64!(7 * 6 + 5, 6));
654        assert_eq!(R64!(-2, 3) + 2, R64!(4, 3));
655        assert_eq!(R64!(2, 3) + 0, R64!(2, 3));
656        assert_eq!(R64!(2, 3) - 2, R64!(-4, 3));
657        assert_eq!(R64!(0) - 1, R64!(-1));
658        assert_eq!(R64!(-2, 3) - 2, R64!(-8, 3));
659    }
660
661    /// Adding an integer to zero has to set the sign as well as the numerator.
662    #[test]
663    fn test_add_to_zero() {
664        assert_eq!(R64!(0) + 1_u64, R64!(1));
665        assert_eq!(R64!(0) + 1_i32, R64!(1));
666        assert_eq!(R64!(0) - 1_u64, R64!(-1));
667        assert_eq!(R64!(0) - 1_i32, R64!(-1));
668
669        let value = R64!(0) + 1_u64;
670        assert!(!value.is_zero());
671        assert!(value.is_not_zero());
672        assert_eq!(value.signum(), Sign::Positive);
673    }
674
675    /// A zero right hand side leaves the value alone; in particular, it doesn't create a zero with
676    /// a sign, which would break the invariant that only a zero numerator has sign `Sign::Zero`.
677    #[test]
678    fn test_add_zero_integer() {
679        for value in [R64!(0), R64!(2, 3), R64!(-2, 3)] {
680            assert_eq!(value + 0_u64, value);
681            assert_eq!(value - 0_u64, value);
682            assert_eq!(value + 0_i64, value);
683            assert_eq!(value - 0_i64, value);
684        }
685
686        let zero = R64!(0) - 0_u64;
687        assert_eq!(zero, R64!(0));
688        assert!(zero.is_zero());
689        assert!(!zero.is_not_zero());
690        assert_eq!(zero.signum(), Sign::Zero);
691    }
692
693    /// A zero has sign `Sign::Zero`, so comparing with an integer can't assume `Sign::Positive`.
694    #[test]
695    fn test_eq_integer() {
696        assert_eq!(R32!(0), 0_u32);
697        assert_eq!(0_u32, R32!(0));
698        assert_eq!(R32!(0), 0_i32);
699        assert_eq!(R32!(3), 3_u32);
700        assert_eq!(R32!(3), NonZeroU32::new(3).unwrap());
701        assert_ne!(R32!(3), 0_u32);
702        assert_ne!(R32!(0), 3_u32);
703        assert_ne!(R32!(-3), 3_u32);
704        assert_ne!(R32!(3, 2), 3_u32);
705    }
706
707    /// The product of the integer with the denominator decides the sign of the result, so it may
708    /// not silently wrap: it is computed in a wider type.
709    #[test]
710    fn test_add_integer_wide_intermediate() {
711        // `130 * 2` doesn't fit in a `u8`, while the result `-5 / 2` does.
712        let value = Rational8::new_signed(Sign::Positive, 255, 2).unwrap();
713        assert_eq!(value - 130_u8, Rational8::new_signed(Sign::Negative, 5, 2).unwrap());
714        assert_eq!(-value + 130_u8, Rational8::new_signed(Sign::Positive, 5, 2).unwrap());
715        assert_eq!(value - 128_u8, Rational8::new_signed(Sign::Negative, 1, 2).unwrap());
716        assert_eq!(value - 127_u8, Rational8::new_signed(Sign::Positive, 1, 2).unwrap());
717
718        // `10_000 * 7` doesn't fit in a `u16`, while the result `-40_000 / 7` does.
719        let value = Rational16::new_signed(Sign::Positive, 30_000, 7).unwrap();
720        assert_eq!(value - 10_000_u16, Rational16::new_signed(Sign::Negative, 40_000, 7).unwrap());
721        assert_eq!(-value + 10_000_u16, Rational16::new_signed(Sign::Positive, 40_000, 7).unwrap());
722    }
723
724    /// The widest type has nothing to widen into, so a product that overflows can't be represented.
725    /// The sign of the result can be, and has to be right.
726    #[cfg(not(debug_assertions))]
727    #[test]
728    fn test_add_integer_widest_intermediate() {
729        use crate::Rational128;
730
731        // `2^127 * 2` wraps to zero, which is smaller than any numerator: without the check on the
732        // product, the subtraction would look like it doesn't pass zero at all. Only the sign of
733        // the result is guaranteed; its magnitude can't be represented in general.
734        let value = Rational128::new_signed(Sign::Positive, u128::MAX, 2).unwrap();
735        assert!((value - (1_u128 << 127)).is_negative());
736        assert!((-value + (1_u128 << 127)).is_positive());
737    }
738
739    #[test]
740    fn test_mul() {
741        let mut x = R16!(1);
742        x /= &19_u16;
743        assert_eq!(x, R16!(1, 19));
744
745        assert_eq!(R16!(1) / &19_u16, R16!(1, 19));
746        assert_eq!(R16!(1) * &19_u16, R16!(19));
747        assert_eq!(R32!(3) * &19, R32!(19 * 3));
748        assert_eq!(R32!(3) / &19, R32!(3, 19));
749        assert_eq!(R32!(3) * &6, R32!(3 * 6));
750        assert_eq!(R32!(3) / &6, R32!(3, 6));
751        assert_eq!(R32!(3) / &(-6), R32!(-3, 6));
752        assert_eq!(R32!(3) * 0, R32!(0));
753        assert_eq!(R32!(3) / &6, R32!(3, 6));
754    }
755
756    #[test]
757    #[should_panic]
758    #[allow(unused_must_use)]
759    fn test_div_by_zero() {
760        R32!(3) / &0;
761    }
762}