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}