relp_num/rational/big/
with_small_rational.rs

1//! # Interactions with fixed size ratios
2use crate::NonZeroUbig;
3use crate::rational::{Rational16, Rational32, Rational64, Rational8};
4use crate::rational::big::Big;
5use crate::sign::Negateable;
6use crate::sign::Sign;
7use crate::Ubig;
8
9macro_rules! define_interations {
10    ($small:ident, $module_name:ident) => {
11        mod $module_name {
12            use super::*;
13
14            mod creation {
15                use super::*;
16
17                impl<const S: usize> From<$small> for Big<S> {
18                    #[must_use]
19                    #[inline]
20                    fn from(value: $small) -> Self {
21                        Self {
22                            sign: value.sign,
23                            numerator: Ubig::new(value.numerator as usize),
24                            denominator: unsafe {
25                                // SAFETY: Input denominator is nonzero
26                                NonZeroUbig::new_unchecked(value.denominator as usize)
27                            },
28                        }
29                    }
30                }
31
32                impl<const S: usize> From<&$small> for Big<S> {
33                    #[must_use]
34                    #[inline]
35                    fn from(value: &$small) -> Self {
36                        Self {
37                            sign: value.sign,
38                            numerator: Ubig::new(value.numerator as usize),
39                            denominator: unsafe {
40                                // SAFETY: Input denominator is nonzero
41                                NonZeroUbig::new_unchecked(value.denominator as usize)
42                            },
43                        }
44                    }
45                }
46            }
47
48            mod compare {
49                use super::*;
50
51                impl<const S: usize> PartialEq<$small> for Big<S> {
52                    #[inline]
53                    fn eq(&self, other: &$small) -> bool {
54                        // Compare first with the denominator, we don't have to do a bounds check
55                        // and the probability that its equal is small
56                        *self.denominator.first() == other.denominator as usize &&
57                            match self.sign {
58                                Sign::Zero => other.sign == Sign::Zero,
59                                Sign::Positive | Sign::Negative => {
60                                    self.numerator[0] == other.numerator as usize &&
61                                    self.numerator.len() == 1 &&
62                                    self.denominator.len() == 1
63                                }
64                            }
65                    }
66                }
67            }
68
69            mod field {
70                use super::*;
71                use crate::sign::Sign;
72
73                mod add {
74                    use super::*;
75                    use std::ops::{Add, AddAssign};
76                    use crate::rational::big::ops::building_blocks::{add_small, sub_small, SignChange};
77
78                    impl<const S: usize> Add<$small> for Big<S> {
79                        type Output = Self;
80
81                        #[must_use]
82                        #[inline]
83                        fn add(mut self, rhs: $small) -> Self::Output {
84                            AddAssign::add_assign(&mut self, &rhs);
85                            self
86                        }
87                    }
88
89                    impl<const S: usize> Add<&$small> for Big<S> {
90                        type Output = Self;
91
92                        #[must_use]
93                        #[inline]
94                        fn add(mut self, rhs: &$small) -> Self::Output {
95                            AddAssign::add_assign(&mut self, rhs);
96                            self
97                        }
98                    }
99
100                    impl<const S: usize> Add<Option<&$small>> for Big<S> {
101                        type Output = Self;
102
103                        #[must_use]
104                        #[inline]
105                        fn add(self, rhs: Option<&$small>) -> Self::Output {
106                            match rhs {
107                                None => self,
108                                Some(rhs) => Add::add(self, rhs),
109                            }
110                        }
111                    }
112
113                    impl<const S: usize> Add<&$small> for &Big<S> {
114                        type Output = Big<S>;
115
116                        #[must_use]
117                        #[inline]
118                        fn add(self, rhs: &$small) -> Self::Output {
119                            // TODO(PERFORMANCE): Make sure that this is just as efficient as a native algorithm.
120                            let mut cloned = self.clone();
121                            AddAssign::add_assign(&mut cloned, rhs);
122                            cloned
123                        }
124                    }
125
126                    impl<const S: usize> Add<Option<&$small>> for &Big<S> {
127                        type Output = Big<S>;
128
129                        #[must_use]
130                        #[inline]
131                        fn add(self, rhs: Option<&$small>) -> Self::Output {
132                            // TODO(PERFORMANCE): Make sure that this is just as efficient as a native algorithm.
133                            let copy = self.clone();
134                            match rhs {
135                                None => copy,
136                                Some(rhs) => Add::add(copy, rhs),
137                            }
138                        }
139                    }
140
141                    impl<const S: usize> AddAssign<$small> for Big<S> {
142                        #[inline]
143                        fn add_assign(&mut self, rhs: $small) {
144                            AddAssign::add_assign(self, &rhs);
145                        }
146                    }
147
148                    impl<const S: usize> AddAssign<&$small> for Big<S> {
149                        #[inline]
150                        fn add_assign(&mut self, rhs: &$small) {
151                            match (self.sign, rhs.sign) {
152                                (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
153                                    unsafe {
154                                        // SAFETY: The numbers are non zero
155                                        add_small(
156                                            self.numerator.inner_mut(),
157                                            self.denominator.inner_mut(),
158                                            rhs.numerator as usize,
159                                            rhs.denominator as usize,
160                                        );
161                                    }
162                                },
163                                (Sign::Negative, Sign::Positive) | (Sign::Positive, Sign::Negative) => {
164                                    unsafe {
165                                        // SAFETY: The numbers are non zero
166                                        let sign_change = sub_small(
167                                            self.numerator.inner_mut(),
168                                            self.denominator.inner_mut(),
169                                            rhs.numerator as usize,
170                                            rhs.denominator as usize,
171                                        );
172                                        match sign_change {
173                                            SignChange::None => {}
174                                            SignChange::Flip => self.sign.negate(),
175                                            SignChange::Zero => self.sign = Sign::Zero,
176                                        }
177                                    }
178                                }
179                                (_, Sign::Zero) => {}
180                                (Sign::Zero, _) => {
181                                    self.sign = rhs.sign;
182                                    debug_assert_eq!(self.numerator.len(), 0);
183                                    unsafe {
184                                        // SAFETY: Value was empty before and rhs.numerator is non zero
185                                        self.numerator.inner_mut().push(rhs.numerator as usize);
186                                    }
187                                    debug_assert_eq!(self.denominator.len(), 1);
188                                    debug_assert_eq!(self.denominator[0], 1);
189                                    unsafe {
190                                        // SAFETY: Value was one before and rhs.denominator is non zero
191                                        *self.denominator.first_mut() = rhs.denominator as usize;
192                                    }
193                                }
194                            }
195                        }
196                    }
197                }
198
199                mod sub {
200                    use super::*;
201                    use crate::rational::big::ops::building_blocks::{add_small, sub_small, SignChange};
202                    use std::ops::{Sub, SubAssign};
203
204                    impl<const S: usize> Sub<$small> for Big<S> {
205                        type Output = Self;
206
207                        #[must_use]
208                        #[inline]
209                        fn sub(mut self, rhs: $small) -> Self::Output {
210                            SubAssign::sub_assign(&mut self, &rhs);
211                            self
212                        }
213                    }
214
215                    impl<const S: usize> Sub<&$small> for Big<S> {
216                        type Output = Self;
217
218                        #[must_use]
219                        #[inline]
220                        fn sub(mut self, rhs: &$small) -> Self::Output {
221                            SubAssign::sub_assign(&mut self, rhs);
222                            self
223                        }
224                    }
225
226                    impl<const S: usize> Sub<Option<&$small>> for Big<S> {
227                        type Output = Self;
228
229                        #[must_use]
230                        #[inline]
231                        fn sub(self, rhs: Option<&$small>) -> Self::Output {
232                            match rhs {
233                                None => self,
234                                Some(rhs) => Sub::sub(self, rhs),
235                            }
236                        }
237                    }
238
239                    impl<const S: usize> Sub<&$small> for &Big<S> {
240                        type Output = Big<S>;
241
242                        #[must_use]
243                        #[inline]
244                        fn sub(self, rhs: &$small) -> Self::Output {
245                            // TODO(PERFORMANCE): Make sure that this is just as efficient as a native algorithm.
246                            let mut cloned = self.clone();
247                            SubAssign::sub_assign(&mut cloned, rhs);
248                            cloned
249                        }
250                    }
251
252                    impl<const S: usize> Sub<Option<&$small>> for &Big<S> {
253                        type Output = Big<S>;
254
255                        #[must_use]
256                        #[inline]
257                        fn sub(self, rhs: Option<&$small>) -> Self::Output {
258                            // TODO(PERFORMANCE): Make sure that this is just as efficient as a native algorithm.
259                            let copy = self.clone();
260                            match rhs {
261                                None => copy,
262                                Some(rhs) => Sub::sub(copy, rhs),
263                            }
264                        }
265                    }
266
267                    impl<const S: usize> SubAssign<$small> for Big<S> {
268                        #[inline]
269                        fn sub_assign(&mut self, rhs: $small) {
270                            SubAssign::sub_assign(self, &rhs);
271                        }
272                    }
273
274                    impl<const S: usize> SubAssign<&$small> for Big<S> {
275                        #[inline]
276                        fn sub_assign(&mut self, rhs: &$small) {
277                            match (self.sign, rhs.sign) {
278                                (Sign::Positive, Sign::Positive) | (Sign::Negative, Sign::Negative) => {
279                                    unsafe {
280                                        // SAFETY: The numbers are non zero
281                                        let sign_change = sub_small(
282                                            self.numerator.inner_mut(),
283                                            self.denominator.inner_mut(),
284                                            rhs.numerator as usize,
285                                            rhs.denominator as usize,
286                                        );
287                                        match sign_change {
288                                            SignChange::None => {}
289                                            SignChange::Flip => self.sign.negate(),
290                                            SignChange::Zero => self.sign = Sign::Zero,
291                                        }
292                                    }
293                                }
294                                (Sign::Negative, Sign::Positive) | (Sign::Positive, Sign::Negative) => {
295                                    unsafe {
296                                        // SAFETY: The numbers are non zero
297                                        add_small(
298                                            self.numerator.inner_mut(),
299                                            self.denominator.inner_mut(),
300                                            rhs.numerator as usize,
301                                            rhs.denominator as usize,
302                                        );
303                                    }
304                                }
305                                (_, Sign::Zero) => {}
306                                (Sign::Zero, _) => {
307                                    self.sign = -rhs.sign;
308                                    debug_assert_eq!(self.numerator.len(), 0);
309                                    unsafe {
310                                        // SAFETY: The rhs numerator is not zero
311                                        self.numerator.inner_mut().push(rhs.numerator as usize)
312                                    };
313                                    debug_assert_eq!(self.denominator.len(), 1);
314                                    debug_assert_eq!(self.denominator[0], 1);
315                                    unsafe {
316                                        // SAFETY: The rhs denominator is not zero
317                                        *self.denominator.first_mut() = rhs.denominator as usize;
318                                    }
319                                }
320                            }
321                        }
322                    }
323                }
324
325                mod mul {
326                    use super::*;
327                    use std::ops::{Mul, MulAssign};
328                    use crate::rational::big::ops::building_blocks::mul_small;
329
330                    impl<const S: usize> Mul<$small> for Big<S> {
331                        type Output = Self;
332
333                        #[must_use]
334                        #[inline]
335                        fn mul(self, rhs: $small) -> Self::Output {
336                            Mul::mul(self, &rhs)
337                        }
338                    }
339
340                    impl<const S: usize> Mul<&$small> for Big<S> {
341                        type Output = Self;
342
343                        #[must_use]
344                        #[inline]
345                        fn mul(mut self, rhs: &$small) -> Self::Output {
346                            MulAssign::mul_assign(&mut self, rhs);
347                            self
348                        }
349                    }
350
351                    impl<const S: usize> Mul<&$small> for &Big<S> {
352                        type Output = Big<S>;
353
354                        #[must_use]
355                        #[inline]
356                        fn mul(self, rhs: &$small) -> Self::Output {
357                            // TODO(PERFORMANCE): Make sure that this is just as efficient as a native algorithm.
358                            self.clone() * rhs
359                        }
360                    }
361
362                    impl<const S: usize> Mul<Option<&$small>> for Big<S> {
363                        type Output = Big<S>;
364
365                        #[must_use]
366                        #[inline]
367                        fn mul(mut self, rhs: Option<&$small>) -> Self::Output {
368                            match rhs {
369                                None => {
370                                    <Self as num_traits::Zero>::set_zero(&mut self);
371                                    self
372                                },
373                                Some(rhs) => Mul::mul(self, rhs),
374                            }
375                        }
376                    }
377
378                    impl<const S: usize> Mul<Option<&$small>> for &Big<S> {
379                        type Output = Big<S>;
380
381                        #[must_use]
382                        #[inline]
383                        fn mul(self, rhs: Option<&$small>) -> Self::Output {
384                            match rhs {
385                                None => <Self::Output as num_traits::Zero>::zero(),
386                                Some(rhs) => Mul::mul(self, rhs),
387                            }
388                        }
389                    }
390
391                    impl<const S: usize> MulAssign<$small> for Big<S> {
392                        #[inline]
393                        fn mul_assign(&mut self, rhs: $small) {
394                            MulAssign::mul_assign(self, &rhs);
395                        }
396                    }
397
398                    impl<const S: usize> MulAssign<&$small> for Big<S> {
399                        #[inline]
400                        fn mul_assign(&mut self, rhs: &$small) {
401                            match (self.sign, rhs.sign) {
402                                (Sign::Positive | Sign::Negative, Sign::Positive | Sign::Negative) => {
403                                    self.sign *= rhs.sign;
404                                    unsafe {
405                                        mul_small(
406                                            self.numerator.inner_mut(),
407                                            self.denominator.inner_mut(),
408                                            rhs.numerator as usize,
409                                            rhs.denominator as usize,
410                                        )
411                                    }
412                                }
413                                (Sign::Positive | Sign::Negative, Sign::Zero) => {
414                                    <Self as num_traits::Zero>::set_zero(self);
415                                }
416                                (Sign::Zero, _) => {}
417                            }
418                        }
419                    }
420                }
421
422                mod div {
423                    use super::*;
424                    use std::ops::{Div, DivAssign};
425                    use crate::rational::big::ops::building_blocks::mul_small;
426
427                    impl<const S: usize> Div<$small> for Big<S> {
428                        type Output = Big<S>;
429
430                        #[must_use]
431                        #[inline]
432                        fn div(mut self, rhs: $small) -> Self::Output {
433                            DivAssign::div_assign(&mut self, rhs);
434                            self
435                        }
436                    }
437
438                    impl<const S: usize> Div<&$small> for Big<S> {
439                        type Output = Big<S>;
440
441                        #[must_use]
442                        #[inline]
443                        fn div(mut self, rhs: &$small) -> Self::Output {
444                            DivAssign::div_assign(&mut self, rhs);
445                            self
446                        }
447                    }
448
449                    impl<const S: usize> DivAssign<$small> for Big<S> {
450                        #[inline]
451                        fn div_assign(&mut self, rhs: $small) {
452                            DivAssign::div_assign(self, &rhs);
453                        }
454                    }
455
456                    impl<const S: usize> DivAssign<&$small> for Big<S> {
457                        #[inline]
458                        fn div_assign(&mut self, rhs: &$small) {
459                            match (self.sign, rhs.sign) {
460                                (Sign::Positive | Sign::Negative, Sign::Positive | Sign::Negative) => {
461                                    self.sign *= rhs.sign;
462                                    unsafe {
463                                        mul_small(
464                                            self.numerator.inner_mut(),
465                                            self.denominator.inner_mut(),
466                                            rhs.denominator as usize,
467                                            rhs.numerator as usize,
468                                        );
469                                    }
470                                }
471                                (Sign::Positive | Sign::Negative, Sign::Zero) => panic!("attempt to divide by zero"),
472                                (Sign::Zero, _) => {}
473                            }
474                        }
475                    }
476                }
477            }
478        }
479    }
480}
481
482define_interations!(Rational8, rational8);
483define_interations!(Rational16, rational16);
484define_interations!(Rational32, rational32);
485define_interations!(Rational64, rational64);
486
487#[cfg(test)]
488mod test {
489    use num_traits::One;
490    use smallvec::smallvec;
491
492    use crate::{R16, R32, R64, R8, RationalBig, RB, Sign, Ubig};
493    use crate::integer::big::NonZeroUbig;
494
495    #[test]
496    fn test_eq() {
497        assert_eq!(RB!(0), R64!(0));
498        assert_eq!(RB!(-2), R64!(-2));
499        assert_eq!(RB!(854984, 6868468468), R64!(854984, 6868468468));
500        assert_eq!(RB!(-989888, 4968468421), R64!(-989888, 4968468421));
501        assert_ne!(RB!(668468498646846546846546898997987_u128), R8!(1));
502        assert_ne!(RB!(668468498646846546846546898997987.4385484_f64), R8!(1, 2));
503    }
504
505    #[test]
506    fn test_add_sub() {
507        assert_eq!(RB!(0) + R8!(0), RB!(0));
508        assert_eq!(RB!(89) + R8!(1), RB!(90));
509        assert_eq!(RB!(89) - R16!(1), RB!(88));
510
511        assert_eq!(RB!(2, 3) + R16!(4, 9), RB!(10, 9));
512        assert_eq!(RB!(989, 141) + R8!(1, 141), RB!(990, 141));
513        assert_eq!(RB!(-84, 3) + R8!(1, 3), RB!(-83, 3));
514        assert_eq!(RB!(1, 2) + R8!(1, 2), RB!(1));
515        assert_eq!(RB!(-1, 2) + R8!(1, 2), RB!(0));
516        assert_eq!(RB!(-1, 2) + R8!(1), RB!(1, 2));
517        assert_eq!(RB!(7, 2) + R8!(5, 2), RB!(6));
518        assert_eq!(RB!(-7, 2) + R8!(5, 2), RB!(-1));
519        assert_eq!(RB!(-7, 2) - R8!(5, 2), RB!(-6));
520        assert_eq!(
521            RationalBig {
522                sign: Sign::Positive,
523                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![1, 1]) },
524                denominator: unsafe { NonZeroUbig::from_inner_unchecked(smallvec![2]) },
525            } + R8!(1, 2),
526            RationalBig {
527                sign: Sign::Positive,
528                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![(1 << 63) + 1]) },
529                denominator: NonZeroUbig::one(),
530            },
531        );
532
533        assert_eq!(RB!(2, 3) + R8!(8, 1), RB!(8 * 3 + 2, 3));
534        assert_eq!(RB!(8) + R8!(16, 3), RB!(8 * 3 + 16, 3));
535        assert_eq!(RB!(3, 5) + R16!(2, 5), RB!(1));
536
537        assert_eq!(RB!(5) - R32!(7), RB!(-2));
538        assert_eq!(
539            RationalBig {
540                sign: Sign::Positive,
541                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![1, 1]) },
542                denominator: unsafe { NonZeroUbig::from_inner_unchecked(smallvec![2]) },
543            } - R8!(1, 2),
544            RationalBig {
545                sign: Sign::Positive,
546                numerator: unsafe { Ubig::from_inner_unchecked(smallvec![1 << 63]) },
547                denominator: NonZeroUbig::one(),
548            },
549        );
550        assert_eq!(RB!(5, 2) - R8!(2), RB!(1, 2));
551        assert_eq!(RB!(3) - R8!(1, 2), RB!(5, 2));
552        assert_eq!(RB!(16, 3) - R8!(11, 4), RB!(16 * 4 - 11 * 3, 12));
553
554        assert_eq!(RB!(0) + R8!(1, 2), RB!(1, 2));
555        assert_eq!(RB!(0) - R8!(3, 4), RB!(-3, 4));
556        assert_eq!(RB!(-10, 4) + R8!(-10, 8), RB!(-15, 4));
557        assert_eq!(RB!(-10, 4) + R64!(1, 4), RB!(-9, 4));
558        assert_eq!(RB!(-10, 8) + R64!(-10, 9), RB!(-5 * 17, 3 * 3 * 2 * 2));
559        assert_eq!(RB!(-5, 4) + R64!(-5, 4), RB!(-5, 2));
560        assert_eq!(RB!(-7, 6) + R64!(-7, 6), RB!(-7, 3));
561
562        let limit = 10;
563        for a in -limit..limit {
564            for b in 1..limit {
565                for c in -limit..limit {
566                    for d in 1..limit {
567                        assert_eq!(RB!(a, b as u64) + R64!(c, d as u64), RB!(a * d + c * b, b as u64 * d as u64), "{} / {} - {} / {}", a, b, c, d);
568                    }
569                }
570            }
571        }
572    }
573
574    #[test]
575    fn test_mul_div() {
576        assert_eq!(RB!(0) * R8!(18), RB!(0));
577        assert_eq!(RB!(1) * R8!(6), RB!(6));
578        assert_eq!(RB!(-1) * R64!(65488846), -RB!(65488846));
579        assert_eq!(RB!(7, 11) * R8!(11, 7), RB!(1));
580        assert_eq!(RB!(7, 11) * R16!(22, 7), RB!(2));
581        assert_eq!(RB!(14, 33) * R32!(3, 2), RB!(7, 11));
582        assert_eq!(RB!(4, 3) * R64!(0), RB!(0));
583
584        let limit = 10;
585        for a in -limit..limit {
586            for b in 1..limit {
587                for c in -limit..limit {
588                    for d in 1..limit {
589                        assert_eq!(RB!(a, b as u64) * R64!(c, d as u64), RB!(a * c, (b * d) as u64), "{} / {} * {} / {}", a, b, c, d);
590                    }
591                }
592            }
593        }
594    }
595}