Skip to main content

relp_num/rational/big/with_integer/
small.rs

1use std::cmp::Ordering;
2use std::num::{NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize};
3use std::num::{NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize};
4use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
5
6use num_traits::{One, Zero};
7use smallvec::{smallvec, SmallVec};
8
9use crate::{NonZeroSign, NonZeroSigned, Signed};
10use crate::{Negateable, NonZero, Sign};
11use crate::integer::big::ops::building_blocks::is_well_formed_non_zero;
12use crate::integer::big::ops::non_zero::{add_assign, is_one_non_zero, mul_assign_single_non_zero, mul_non_zero, subtracting_cmp};
13use crate::integer::big::ops::normalize::simplify_fraction_gcd_single;
14use crate::rational::big::{Big, NonZeroBig};
15
16macro_rules! forwards {
17    ($ty:ty, $large:ty) => {
18        impl<const S: usize> Add<$ty> for $large {
19            type Output = Self;
20
21            #[inline]
22            fn add(mut self, rhs: $ty) -> Self::Output {
23                AddAssign::add_assign(&mut self, rhs);
24                self
25            }
26        }
27
28        impl<const S: usize> Add<&$ty> for $large {
29            type Output = Self;
30
31            #[inline]
32            fn add(mut self, rhs: &$ty) -> Self::Output {
33                AddAssign::add_assign(&mut self, rhs);
34                self
35            }
36        }
37
38        impl<const S: usize> Add<$ty> for &$large {
39            type Output = $large;
40
41            #[inline]
42            fn add(self, rhs: $ty) -> Self::Output {
43                Add::add(self.clone(), rhs)
44            }
45        }
46
47        impl<const S: usize> Add<&$ty> for &$large {
48            type Output = $large;
49
50            #[inline]
51            fn add(self, rhs: &$ty) -> Self::Output {
52                Add::add(self, *rhs)
53            }
54        }
55
56        impl<const S: usize> AddAssign<&$ty> for $large {
57            #[inline]
58            fn add_assign(&mut self, rhs: &$ty) {
59                AddAssign::add_assign(self, *rhs);
60            }
61        }
62
63        impl<const S: usize> Sub<$ty> for $large {
64            type Output = Self;
65
66            #[inline]
67            fn sub(mut self, rhs: $ty) -> Self::Output {
68                SubAssign::sub_assign(&mut self, rhs);
69                self
70            }
71        }
72
73        impl<const S: usize> Sub<&$ty> for $large {
74            type Output = Self;
75
76            #[inline]
77            fn sub(mut self, rhs: &$ty) -> Self::Output {
78                SubAssign::sub_assign(&mut self, rhs);
79                self
80            }
81        }
82
83        impl<const S: usize> Sub<$ty> for &$large {
84            type Output = $large;
85
86            #[inline]
87            fn sub(self, rhs: $ty) -> Self::Output {
88                Sub::sub(self.clone(), rhs)
89            }
90        }
91
92        impl<const S: usize> Sub<&$ty> for &$large {
93            type Output = $large;
94
95            #[inline]
96            fn sub(self, rhs: &$ty) -> Self::Output {
97                Sub::sub(self, *rhs)
98            }
99        }
100
101        impl<const S: usize> SubAssign<&$ty> for $large {
102            #[inline]
103            fn sub_assign(&mut self, rhs: &$ty) {
104                SubAssign::sub_assign(self, *rhs);
105            }
106        }
107
108        impl<const S: usize> Mul<$ty> for $large {
109            type Output = Self;
110
111            #[inline]
112            fn mul(mut self, rhs: $ty) -> Self::Output {
113                MulAssign::mul_assign(&mut self, rhs);
114                self
115            }
116        }
117
118        impl<const S: usize> Mul<&$ty> for $large {
119            type Output = Self;
120
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<const S: usize> Mul<$ty> for &$large {
129            type Output = $large;
130
131            #[inline]
132            fn mul(self, rhs: $ty) -> Self::Output {
133                Mul::mul(self.clone(), rhs)
134            }
135        }
136
137        impl<const S: usize> Mul<&$ty> for &$large {
138            type Output = $large;
139
140            #[inline]
141            fn mul(self, rhs: &$ty) -> Self::Output {
142                Mul::mul(self, *rhs)
143            }
144        }
145
146        impl<const S: usize> MulAssign<&$ty> for $large {
147            #[inline]
148            fn mul_assign(&mut self, rhs: &$ty) {
149                MulAssign::mul_assign(self, *rhs);
150            }
151        }
152
153        impl<const S: usize> Div<$ty> for $large {
154            type Output = Self;
155
156            #[inline]
157            fn div(mut self, rhs: $ty) -> Self::Output {
158                DivAssign::div_assign(&mut self, rhs);
159                self
160            }
161        }
162
163        impl<const S: usize> Div<&$ty> for $large {
164            type Output = Self;
165
166            #[inline]
167            fn div(mut self, rhs: &$ty) -> Self::Output {
168                DivAssign::div_assign(&mut self, rhs);
169                self
170            }
171        }
172
173        impl<const S: usize> Div<$ty> for &$large {
174            type Output = $large;
175
176            #[inline]
177            fn div(self, rhs: $ty) -> Self::Output {
178                Div::div(self.clone(), rhs)
179            }
180        }
181
182        impl<const S: usize> Div<&$ty> for &$large {
183            type Output = $large;
184
185            #[inline]
186            fn div(self, rhs: &$ty) -> Self::Output {
187                Div::div(self, *rhs)
188            }
189        }
190
191        impl<const S: usize> DivAssign<&$ty> for $large {
192            #[inline]
193            fn div_assign(&mut self, rhs: &$ty) {
194                DivAssign::div_assign(self, *rhs);
195            }
196        }
197    }
198}
199
200forwards!(u8, Big<S>);
201forwards!(u16, Big<S>);
202forwards!(u32, Big<S>);
203forwards!(u64, Big<S>);
204forwards!(usize, Big<S>);
205forwards!(NonZeroU8, Big<S>);
206forwards!(NonZeroU16, Big<S>);
207forwards!(NonZeroU32, Big<S>);
208forwards!(NonZeroU64, Big<S>);
209forwards!(NonZeroUsize, Big<S>);
210forwards!(i8, Big<S>);
211forwards!(i16, Big<S>);
212forwards!(i32, Big<S>);
213forwards!(i64, Big<S>);
214forwards!(isize, Big<S>);
215forwards!(NonZeroI8, Big<S>);
216forwards!(NonZeroI16, Big<S>);
217forwards!(NonZeroI32, Big<S>);
218forwards!(NonZeroI64, Big<S>);
219forwards!(NonZeroIsize, Big<S>);
220
221forwards!(u8, NonZeroBig<S>);
222forwards!(u16, NonZeroBig<S>);
223forwards!(u32, NonZeroBig<S>);
224forwards!(u64, NonZeroBig<S>);
225forwards!(usize, NonZeroBig<S>);
226forwards!(NonZeroU8, NonZeroBig<S>);
227forwards!(NonZeroU16, NonZeroBig<S>);
228forwards!(NonZeroU32, NonZeroBig<S>);
229forwards!(NonZeroU64, NonZeroBig<S>);
230forwards!(NonZeroUsize, NonZeroBig<S>);
231forwards!(i8, NonZeroBig<S>);
232forwards!(i16, NonZeroBig<S>);
233forwards!(i32, NonZeroBig<S>);
234forwards!(i64, NonZeroBig<S>);
235forwards!(isize, NonZeroBig<S>);
236forwards!(NonZeroI8, NonZeroBig<S>);
237forwards!(NonZeroI16, NonZeroBig<S>);
238forwards!(NonZeroI32, NonZeroBig<S>);
239forwards!(NonZeroI64, NonZeroBig<S>);
240forwards!(NonZeroIsize, NonZeroBig<S>);
241
242macro_rules! impls {
243    ($ty:ty, $nzty:ty, $sty:ty, $nzsty:ty, $large:ty) => {
244        impl<const S: usize> AddAssign<$ty> for $large {
245            #[inline]
246            fn add_assign(&mut self, rhs: $ty) {
247                if rhs.is_not_zero() {
248                    unsafe {
249                        // SAFETY: rhs is non zero
250                        self.add_assign_single_int_non_zero(rhs as usize);
251                    }
252                }
253            }
254        }
255
256        impl<const S: usize> AddAssign<$nzty> for $large {
257            #[inline]
258            fn add_assign(&mut self, rhs: $nzty) {
259                unsafe {
260                    // SAFETY: rhs is non zero
261                    self.add_assign_single_int_non_zero(rhs.get() as usize);
262                }
263            }
264        }
265
266        impl<const S: usize> AddAssign<$sty> for $large {
267            #[inline]
268            fn add_assign(&mut self, rhs: $sty) {
269                match Signed::signum(&rhs) {
270                    Sign::Positive => unsafe {
271                        // SAFETY: rhs is non zero
272                        self.add_assign_single_int_non_zero(rhs as usize);
273                    }
274                    Sign::Zero => {}
275                    Sign::Negative => unsafe {
276                        // SAFETY: rhs is non zero
277                        self.sub_assign_single_int_non_zero(rhs.unsigned_abs() as usize);
278                    }
279                }
280            }
281        }
282
283        impl<const S: usize> AddAssign<$nzsty> for $large {
284            #[inline]
285            fn add_assign(&mut self, rhs: $nzsty) {
286                match NonZeroSigned::non_zero_signum(&rhs) {
287                    NonZeroSign::Positive => unsafe {
288                        // SAFETY: rhs is non zero
289                        self.add_assign_single_int_non_zero(rhs.get() as usize);
290                    }
291                    NonZeroSign::Negative => unsafe {
292                        // SAFETY: rhs is non zero
293                        self.sub_assign_single_int_non_zero(rhs.get().unsigned_abs() as usize);
294                    }
295                }
296            }
297        }
298
299        impl<const S: usize> SubAssign<$ty> for $large {
300            #[inline]
301            fn sub_assign(&mut self, rhs: $ty) {
302                if rhs.is_not_zero() {
303                    unsafe {
304                        // SAFETY: rhs is non zero
305                        self.sub_assign_single_int_non_zero(rhs as usize);
306                    }
307                }
308            }
309        }
310
311        impl<const S: usize> SubAssign<$nzty> for $large {
312            #[inline]
313            fn sub_assign(&mut self, rhs: $nzty) {
314                unsafe {
315                    // SAFETY: rhs is non zero
316                    self.sub_assign_single_int_non_zero(rhs.get() as usize);
317                }
318            }
319        }
320
321        impl<const S: usize> SubAssign<$sty> for $large {
322            #[inline]
323            fn sub_assign(&mut self, rhs: $sty) {
324                match Signed::signum(&rhs) {
325                    Sign::Positive => unsafe {
326                        // SAFETY: rhs is non zero
327                        self.sub_assign_single_int_non_zero(rhs as usize);
328                    }
329                    Sign::Zero => {}
330                    Sign::Negative => unsafe {
331                        // SAFETY: rhs is non zero
332                        self.add_assign_single_int_non_zero(rhs.unsigned_abs() as usize);
333                    }
334                }
335            }
336        }
337
338        impl<const S: usize> SubAssign<$nzsty> for $large {
339            #[inline]
340            fn sub_assign(&mut self, rhs: $nzsty) {
341                match NonZeroSigned::non_zero_signum(&rhs) {
342                    NonZeroSign::Positive => unsafe {
343                        // SAFETY: rhs is non zero
344                        self.sub_assign_single_int_non_zero(rhs.get() as usize);
345                    }
346                    NonZeroSign::Negative => unsafe {
347                        // SAFETY: rhs is non zero
348                        self.add_assign_single_int_non_zero(rhs.get().unsigned_abs() as usize);
349                    }
350                }
351            }
352        }
353
354        impl<const S: usize> MulAssign<$nzty> for $large {
355            #[inline]
356            fn mul_assign(&mut self, rhs: $nzty) {
357                if self.is_not_zero() {
358                    unsafe {
359                        // SAFETY: self and rhs are non zero
360                        mul_assign_single_int_non_zero(
361                            self.numerator.inner_mut(),
362                            self.denominator.inner_mut(),
363                            rhs.get() as usize,
364                        );
365                    }
366                }
367            }
368        }
369
370        impl<const S: usize> MulAssign<$nzsty> for $large {
371            #[inline]
372            fn mul_assign(&mut self, rhs: $nzsty) {
373                if self.is_not_zero() {
374                    unsafe {
375                        // SAFETY: self and rhs are non zero
376                        mul_assign_single_int_non_zero(
377                            self.numerator.inner_mut(),
378                            self.denominator.inner_mut(),
379                            rhs.get().unsigned_abs() as usize,
380                        );
381                    }
382
383                    if rhs.is_negative() {
384                        self.sign.negate();
385                    }
386                }
387            }
388        }
389
390        impl<const S: usize> DivAssign<$ty> for $large {
391            #[inline]
392            fn div_assign(&mut self, rhs: $ty) {
393                if rhs.is_not_zero() {
394                    if self.is_not_zero() {
395                        unsafe {
396                            // SAFETY: self and rhs are non zero
397                            mul_assign_single_int_non_zero(
398                                self.denominator.inner_mut(),
399                                self.numerator.inner_mut(),
400                                rhs as usize,
401                            );
402                        }
403                    }
404                } else {
405                    panic!("attempt to divide by zero");
406                }
407            }
408        }
409
410        impl<const S: usize> DivAssign<$nzty> for $large {
411            #[inline]
412            fn div_assign(&mut self, rhs: $nzty) {
413                if self.is_not_zero() {
414                    unsafe {
415                        // SAFETY: self and rhs are non zero
416                        mul_assign_single_int_non_zero(
417                            self.denominator.inner_mut(),
418                            self.numerator.inner_mut(),
419                            rhs.get() as usize,
420                        );
421                    }
422                }
423            }
424        }
425
426        impl<const S: usize> DivAssign<$sty> for $large {
427            #[inline]
428            fn div_assign(&mut self, rhs: $sty) {
429                if rhs.is_not_zero() {
430                    if self.is_not_zero() {
431                        unsafe {
432                            // SAFETY: self and rhs are non zero
433                            mul_assign_single_int_non_zero(
434                                self.denominator.inner_mut(),
435                                self.numerator.inner_mut(),
436                                rhs.unsigned_abs() as usize,
437                            );
438                        }
439
440                        if rhs.is_negative() {
441                            self.sign.negate();
442                        }
443                    }
444                } else {
445                    panic!("attempt to divide by zero");
446                }
447            }
448        }
449
450        impl<const S: usize> DivAssign<$nzsty> for $large {
451            #[inline]
452            fn div_assign(&mut self, rhs: $nzsty) {
453                if self.is_not_zero() {
454                    unsafe {
455                        // SAFETY: self and rhs are non zero
456                        mul_assign_single_int_non_zero(
457                            self.denominator.inner_mut(),
458                            self.numerator.inner_mut(),
459                            rhs.get().unsigned_abs() as usize,
460                        );
461                    }
462
463                    if rhs.is_negative() {
464                        self.sign.negate();
465                    }
466                }
467            }
468        }
469    }
470}
471
472impls!(u8, NonZeroU8, i8, NonZeroI8, Big<S>);
473impls!(u16, NonZeroU16, i16, NonZeroI16, Big<S>);
474impls!(u32, NonZeroU32, i32, NonZeroI32, Big<S>);
475impls!(u64, NonZeroU64, i64, NonZeroI64, Big<S>);
476impls!(usize, NonZeroUsize, isize, NonZeroIsize, Big<S>);
477
478impls!(u8, NonZeroU8, i8, NonZeroI8, NonZeroBig<S>);
479impls!(u16, NonZeroU16, i16, NonZeroI16, NonZeroBig<S>);
480impls!(u32, NonZeroU32, i32, NonZeroI32, NonZeroBig<S>);
481impls!(u64, NonZeroU64, i64, NonZeroI64, NonZeroBig<S>);
482impls!(usize, NonZeroUsize, isize, NonZeroIsize, NonZeroBig<S>);
483
484macro_rules! impls_set_zero {
485    ($ty:ty, $sty:ty) => {
486        impl<const S: usize> MulAssign<$ty> for Big<S> {
487            #[inline]
488            fn mul_assign(&mut self, rhs: $ty) {
489                if self.is_not_zero() {
490                    if rhs.is_not_zero() {
491                        unsafe {
492                            // SAFETY: self and rhs are non zero
493                            mul_assign_single_int_non_zero(
494                                self.numerator.inner_mut(),
495                                self.denominator.inner_mut(),
496                                rhs as usize,
497                            );
498                        }
499                    } else {
500                        self.set_zero();
501                    }
502                }
503            }
504        }
505
506        impl<const S: usize> MulAssign<$sty> for Big<S> {
507            #[inline]
508            fn mul_assign(&mut self, rhs: $sty) {
509                if self.is_not_zero() {
510                    match Signed::signum(&rhs) {
511                        Sign::Positive => unsafe {
512                            // SAFETY: self and rhs are non zero
513                            mul_assign_single_int_non_zero(
514                                self.numerator.inner_mut(),
515                                self.denominator.inner_mut(),
516                                rhs as usize,
517                            );
518                        }
519                        Sign::Zero => self.set_zero(),
520                        Sign::Negative => {
521                            unsafe {
522                                // SAFETY: self and rhs are non zero
523                                mul_assign_single_int_non_zero(
524                                    self.numerator.inner_mut(),
525                                    self.denominator.inner_mut(),
526                                    rhs.unsigned_abs() as usize,
527                                );
528                            }
529                            self.sign.negate();
530                        }
531                    }
532                }
533            }
534        }
535    }
536}
537
538impls_set_zero!(u8, i8);
539impls_set_zero!(u16, i16);
540impls_set_zero!(u32, i32);
541impls_set_zero!(u64, i64);
542impls_set_zero!(usize, isize);
543
544macro_rules! impls_not_become_zero {
545    ($ty:ty, $sty:ty) => {
546        impl<const S: usize> MulAssign<$ty> for NonZeroBig<S> {
547            #[inline]
548            fn mul_assign(&mut self, rhs: $ty) {
549                if self.is_not_zero() {
550                    if rhs.is_not_zero() {
551                        unsafe {
552                            // SAFETY: self and rhs are non zero
553                            mul_assign_single_int_non_zero(
554                                self.numerator.inner_mut(),
555                                self.denominator.inner_mut(),
556                                rhs as usize,
557                            );
558                        }
559                    } else {
560                        panic!("attempt to multiply by zero");
561                    }
562                }
563            }
564        }
565
566        impl<const S: usize> MulAssign<$sty> for NonZeroBig<S> {
567            #[inline]
568            fn mul_assign(&mut self, rhs: $sty) {
569                if self.is_not_zero() {
570                    match Signed::signum(&rhs) {
571                        Sign::Positive => unsafe {
572                            // SAFETY: self and rhs are non zero
573                            mul_assign_single_int_non_zero(
574                                self.numerator.inner_mut(),
575                                self.denominator.inner_mut(),
576                                rhs as usize,
577                            );
578                        }
579                        Sign::Zero => panic!("attempt to multiply by zero"),
580                        Sign::Negative => {
581                            unsafe {
582                                // SAFETY: self and rhs are non zero
583                                mul_assign_single_int_non_zero(
584                                    self.numerator.inner_mut(),
585                                    self.denominator.inner_mut(),
586                                    rhs.unsigned_abs() as usize,
587                                );
588                            }
589                            self.sign.negate();
590                        }
591                    }
592                }
593            }
594        }
595    }
596}
597
598impls_not_become_zero!(u8, i8);
599impls_not_become_zero!(u16, i16);
600impls_not_become_zero!(u32, i32);
601impls_not_become_zero!(u64, i64);
602impls_not_become_zero!(usize, isize);
603
604impl<const S: usize> Big<S> {
605    #[inline]
606    unsafe fn add_assign_single_int_non_zero(&mut self, rhs: usize) {
607        debug_assert!(rhs.is_not_zero());
608
609        match self.sign {
610            Sign::Positive => {
611                // Multiplying into a fresh value rather than cloning the denominator and
612                // multiplying in place: the clone allocates for the denominator's own length and
613                // the product is a word longer as often as not, so the in place form pays for a
614                // second allocation to grow into.
615                // SAFETY: The denominator is well formed and not zero, and so is a single word
616                // holding a non zero `rhs`.
617                let difference = unsafe { mul_non_zero::<S>(&self.denominator, &[rhs]) };
618                // SAFETY: The `inner_mut` hands out the numerator's words. Adding a magnitude to a
619                // non zero numerator leaves it well formed and non zero, and leaves the fraction in
620                // lowest terms, because the added term is a multiple of the denominator and so
621                // shares no new factor with it.
622                unsafe { add_assign(self.numerator.inner_mut(), &difference) }
623            },
624            Sign::Zero => {
625                // SAFETY: `rhs` is not zero by the caller's guarantee, so a single word holding it
626                // is well formed. The denominator is one for a zero value, so the fraction stays in
627                // lowest terms, and the sign is set to match just below.
628                unsafe { *self.numerator.inner_mut() = smallvec![rhs] };
629                self.sign = Sign::Positive;
630                debug_assert!(self.denominator.is_one());
631            }
632            Sign::Negative => {
633                // SAFETY: As in the positive arm.
634                let difference = unsafe { mul_non_zero::<S>(&self.denominator, &[rhs]) };
635                // SAFETY: As in the positive arm, except that `subtracting_cmp` leaves the
636                // numerator holding the magnitude of the difference, which may be zero. The match
637                // below restores the sign, and with it the invariant, for each of the outcomes.
638                let ordering = unsafe { subtracting_cmp(self.numerator.inner_mut(), &difference) };
639
640                match ordering {
641                    Ordering::Less => self.sign.negate(),
642                    Ordering::Equal => self.set_zero(),
643                    Ordering::Greater => {}
644                }
645            }
646        }
647    }
648
649    #[inline]
650    unsafe fn sub_assign_single_int_non_zero(&mut self, rhs: usize) {
651        debug_assert!(rhs.is_not_zero());
652
653        match self.sign {
654            Sign::Positive => {
655                // Multiplying into a fresh value rather than cloning and multiplying in place;
656                // see `Big::add_assign_single_int_non_zero` for why.
657                // SAFETY: The denominator is well formed and not zero, and so is a single word
658                // holding a non zero `rhs`.
659                let difference = unsafe { mul_non_zero::<S>(&self.denominator, &[rhs]) };
660                // SAFETY: The `inner_mut` hands out the numerator's words, and `subtracting_cmp`
661                // leaves them holding the magnitude of the difference, which may be zero. The match
662                // below restores the sign, and with it the invariant, for each of the outcomes.
663                let ordering = unsafe { subtracting_cmp(self.numerator.inner_mut(), &difference) };
664
665                match ordering {
666                    Ordering::Less => self.sign.negate(),
667                    Ordering::Equal => self.set_zero(),
668                    Ordering::Greater => {}
669                }
670            }
671            Sign::Zero => {
672                // SAFETY: `rhs` is not zero by the caller's guarantee, so a single word holding it
673                // is well formed. The denominator is one for a zero value, so the fraction stays in
674                // lowest terms, and the sign is set to match just below.
675                unsafe { *self.numerator.inner_mut() = smallvec![rhs] };
676                self.sign = Sign::Negative;
677                debug_assert!(self.denominator.is_one());
678            }
679            Sign::Negative => {
680                // Multiplying into a fresh value rather than cloning and multiplying in place;
681                // see `Big::add_assign_single_int_non_zero` for why.
682                // SAFETY: The denominator is well formed and not zero, and so is a single word
683                // holding a non zero `rhs`.
684                let difference = unsafe { mul_non_zero::<S>(&self.denominator, &[rhs]) };
685                // SAFETY: Adding a magnitude to a non zero numerator leaves it well formed and non
686                // zero, and the added term is a multiple of the denominator, so the fraction stays
687                // in lowest terms.
688                unsafe { add_assign(self.numerator.inner_mut(), &difference) }
689            },
690        }
691    }
692}
693
694impl<const S: usize> NonZeroBig<S> {
695    #[inline]
696    unsafe fn add_assign_single_int_non_zero(&mut self, rhs: usize) {
697        debug_assert!(rhs.is_not_zero());
698
699        // Multiplying into a fresh value rather than cloning and multiplying in place; see
700        // `Big::add_assign_single_int_non_zero` for why.
701        // SAFETY: The denominator is well formed and not zero, and so is a single word holding a
702        // non zero `rhs`.
703        let difference = unsafe { mul_non_zero::<S>(&self.denominator, &[rhs]) };
704
705        match self.sign {
706            NonZeroSign::Positive => {
707                // SAFETY: The `inner_mut` hands out the numerator's words. Adding a magnitude to a
708                // non zero numerator leaves it well formed and non zero, and the added term is a
709                // multiple of the denominator, so the fraction stays in lowest terms.
710                unsafe { add_assign(self.numerator.inner_mut(), &difference) }
711            },
712            NonZeroSign::Negative => {
713                // SAFETY: As above, except that `subtracting_cmp` leaves the numerator holding the
714                // magnitude of the difference. A `NonZeroBig` has no zero representation, so the
715                // equal case panics rather than leaving one behind, and the other two restore the
716                // sign to match the new magnitude.
717                let ordering = unsafe { subtracting_cmp(self.numerator.inner_mut(), &difference) };
718
719                match ordering {
720                    Ordering::Less => self.sign.negate(),
721                    Ordering::Equal => panic!("attempt to add resulting in zero"),
722                    Ordering::Greater => {}
723                }
724            }
725        }
726    }
727
728    #[inline]
729    unsafe fn sub_assign_single_int_non_zero(&mut self, rhs: usize) {
730        debug_assert!(rhs.is_not_zero());
731
732        match self.sign {
733            NonZeroSign::Positive => {
734                // Multiplying into a fresh value rather than cloning and multiplying in place;
735                // see `Big::add_assign_single_int_non_zero` for why.
736                // SAFETY: The denominator is well formed and not zero, and so is a single word
737                // holding a non zero `rhs`.
738                let difference = unsafe { mul_non_zero::<S>(&self.denominator, &[rhs]) };
739                // SAFETY: The `inner_mut` hands out the numerator's words, and `subtracting_cmp`
740                // leaves them holding the magnitude of the difference. A `NonZeroBig` has no zero
741                // representation, so the equal case panics rather than leaving one behind, and the
742                // other two restore the sign to match the new magnitude.
743                let ordering = unsafe { subtracting_cmp(self.numerator.inner_mut(), &difference) };
744
745                match ordering {
746                    Ordering::Less => self.sign.negate(),
747                    Ordering::Equal => panic!("attempt to subtract resulting in zero"),
748                    Ordering::Greater => {}
749                }
750            }
751            NonZeroSign::Negative => {
752                // Multiplying into a fresh value rather than cloning and multiplying in place;
753                // see `Big::add_assign_single_int_non_zero` for why.
754                // SAFETY: The denominator is well formed and not zero, and so is a single word
755                // holding a non zero `rhs`.
756                let difference = unsafe { mul_non_zero::<S>(&self.denominator, &[rhs]) };
757                // SAFETY: Adding a magnitude to a non zero numerator leaves it well formed and non
758                // zero, and the added term is a multiple of the denominator, so the fraction stays
759                // in lowest terms.
760                unsafe { add_assign(self.numerator.inner_mut(), &difference) }
761            },
762        }
763    }
764}
765
766#[inline]
767unsafe fn mul_assign_single_int_non_zero<const S: usize>(
768    numerator: &mut SmallVec<[usize; S]>,
769    denominator: &mut SmallVec<[usize; S]>,
770    mut rhs: usize,
771) {
772    debug_assert!(rhs.is_not_zero());
773    debug_assert!(is_well_formed_non_zero(numerator));
774    debug_assert!(is_well_formed_non_zero(denominator));
775
776    if !rhs.is_one() {
777        // SAFETY: The denominator is non zero and so not empty.
778        if !unsafe { is_one_non_zero(denominator) } {
779            // SAFETY: The denominator is well formed, not empty and not one by the check above.
780            // `rhs` is not zero by the caller's guarantee and not one by the check above.
781            rhs = unsafe { simplify_fraction_gcd_single(denominator, rhs) };
782        }
783        mul_assign_single_non_zero(numerator, rhs);
784    }
785}
786
787#[cfg(test)]
788mod test {
789    use num_traits::{One, Zero};
790
791    use crate::RB;
792    use crate::rational::big::NonZeroBig;
793
794    #[test]
795    fn add() {
796        assert_eq!(RB!(2, 3) + 2, RB!(8, 3));
797        assert_eq!(RB!(5, 6) + 7, RB!(7 * 6 + 5, 6));
798        assert_eq!(RB!(5, 6) - 7, RB!(-7 * 6 + 5, 6));
799        assert_eq!(RB!(5, 6) + -7_i32, RB!(-7 * 6 + 5, 6));
800        assert_eq!(RB!(-5, 6) + 7, RB!(7 * 6 - 5, 6));
801        assert_eq!(RB!(-5, 6) + (-7), -RB!(7 * 6 + 5, 6));
802        assert_eq!(RB!(-2, 3) + 2, RB!(4, 3));
803        assert_eq!(RB!(2, 3) + 0, RB!(2, 3));
804        assert_eq!(RB!(2, 3) - 2, RB!(-4, 3));
805        assert_eq!(RB!(0) - 1, RB!(-1));
806        assert_eq!(RB!(-2, 3) - 2, RB!(-8, 3));
807    }
808
809    #[test]
810    fn mul() {
811        assert_eq!(RB!(2, 3) * 2, RB!(4, 3));
812        assert_eq!(RB!(-2, 3) * 2, RB!(-4, 3));
813        assert_eq!(RB!(2, 3) * 0, RB!(0));
814        assert_eq!(RB!(2, 3) / 2, RB!(1, 3));
815        assert_eq!(RB!(-1) / 1, RB!(-1));
816        assert_eq!(RB!(-2, 3) / 2, RB!(-1, 3));
817    }
818
819    #[test]
820    #[should_panic]
821    #[allow(unused_must_use)]
822    fn mul_zero() {
823        NonZeroBig::<1>::one() * 0_i64;
824    }
825
826    #[test]
827    #[should_panic]
828    #[allow(unused_must_use)]
829    fn add_zero() {
830        NonZeroBig::<1>::one() - 1;
831    }
832
833    /// `-a / b + n` can cancel exactly: `subtracting_cmp` then returns `Ordering::Equal` and leaves
834    /// the numerator empty, so the sign has to be reset as well.
835    #[test]
836    fn add_single_int_cancelling_to_zero() {
837        let mut x = RB!(-5);
838        x += 5_u64;
839        assert!(x.is_zero());
840        assert_eq!(x, RB!(0));
841        assert_eq!(format!("{:?}", x), "0");
842
843        // Same code path, reached through the signed subtraction of a positive value.
844        let mut y = RB!(5);
845        y += -5_i64;
846        assert!(y.is_zero());
847        assert_eq!(y, RB!(0));
848        assert_eq!(format!("{:?}", y), "0");
849    }
850
851    /// See `add_single_int_cancelling_to_zero`, the mirrored case `a / b - n`.
852    #[test]
853    fn sub_single_int_cancelling_to_zero() {
854        let mut x = RB!(5);
855        x -= 5_u64;
856        assert!(x.is_zero());
857        assert_eq!(x, RB!(0));
858        assert_eq!(format!("{:?}", x), "0");
859
860        let mut y = RB!(-5);
861        y -= -5_i64;
862        assert!(y.is_zero());
863        assert_eq!(y, RB!(0));
864        assert_eq!(format!("{:?}", y), "0");
865    }
866
867    /// Adding to zero has to set the sign, just like subtracting from zero does.
868    #[test]
869    fn add_single_int_to_zero_sets_sign() {
870        let mut x = RB!(0);
871        x += 1_u64;
872        assert!(!x.is_zero());
873        assert_eq!(x, RB!(1));
874        assert_eq!(format!("{:?}", x), "1");
875
876        let mut y = RB!(0);
877        y -= -7_i64;
878        assert!(!y.is_zero());
879        assert_eq!(y, RB!(7));
880        assert_eq!(format!("{:?}", y), "7");
881    }
882}