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 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 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 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 #[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 #[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 #[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 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
628shared!(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 #[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 #[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 #[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 #[test]
710 fn test_add_integer_wide_intermediate() {
711 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 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 #[cfg(not(debug_assertions))]
727 #[test]
728 fn test_add_integer_widest_intermediate() {
729 use crate::Rational128;
730
731 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}