Skip to main content

relp_num/integer/big/ops/
mod.rs

1use std::hint::assert_unchecked;
2use std::ops::{Add, AddAssign, Mul};
3
4use num_traits::Zero;
5
6use crate::integer::big::{NonZeroUbig, Ubig};
7use crate::integer::big::ops::building_blocks::add_assign_slice;
8use crate::integer::big::ops::non_zero::{add_assign, mul_non_zero};
9
10pub(crate) mod building_blocks;
11pub mod non_zero;
12pub mod div;
13pub mod normalize;
14
15
16impl<const S: usize> Add for Ubig<S> {
17    type Output = Self;
18
19    #[inline]
20    fn add(self, rhs: Self) -> Self::Output {
21        let (mut left, right) = if rhs.0.len() > self.0.len() {
22            (rhs, self)
23        } else {
24            (self, rhs)
25        };
26
27        if right.is_zero() {
28            return left;
29        }
30
31        unsafe {
32            // SAFETY: Last value can only become zero with overflow, which is accounted for
33            let overflow = add_assign_slice(left.inner_mut(), &right);
34            if overflow {
35                left.inner_mut().push(1);
36            }
37        }
38
39        left
40    }
41}
42
43
44impl<const S: usize> Add for NonZeroUbig<S> {
45    type Output = Self;
46
47    #[inline]
48    fn add(self, rhs: Self) -> Self::Output {
49        let (mut left, right) = if rhs.0.len() > self.0.len() {
50            (rhs, self)
51        } else {
52            (self, rhs)
53        };
54
55        left += &right;
56
57        left
58    }
59}
60
61
62impl<const S: usize> AddAssign<&Self> for Ubig<S> {
63    #[inline]
64    fn add_assign(&mut self, rhs: &Ubig<S>) {
65        add_assign(&mut self.0, &rhs.0);
66    }
67}
68
69impl<const S: usize> AddAssign<&Self> for NonZeroUbig<S> {
70    #[inline]
71    fn add_assign(&mut self, rhs: &Self) {
72        unsafe {
73            // SAFETY: Is non zero so not empty
74            assert_unchecked(!self.0.is_empty());
75            assert_unchecked(!rhs.0.is_empty());
76        }
77        add_assign(&mut self.0, &rhs.0);
78    }
79}
80
81impl<const S: usize> Mul for Ubig<S> {
82    type Output = Self;
83
84    fn mul(mut self, rhs: Self) -> Self::Output {
85        if !self.is_zero() && !rhs.is_zero() {
86            unsafe {
87                // SAFETY: Are not empty so not zero
88                Self(mul_non_zero(&self.0, &rhs.0))
89            }
90        } else {
91            self.set_zero();
92            self
93        }
94    }
95}
96
97impl<const S: usize> Mul for NonZeroUbig<S> {
98    type Output = Self;
99
100    fn mul(self, rhs: Self) -> Self::Output {
101        unsafe {
102            // SAFETY: Are not empty so not zero
103            Self(mul_non_zero(&self.0, &rhs.0))
104        }
105    }
106}
107
108#[cfg(test)]
109mod test {
110    use std::str::FromStr;
111
112    use num_traits::One;
113    use smallvec::smallvec;
114
115    use crate::{NonZeroUbig, Ubig};
116
117    #[test]
118    fn test_add() {
119        assert_eq!(Ubig::<8>::from(0) + Ubig::<8>::from(0), Ubig::<8>::from(0));
120        assert_eq!(Ubig::<8>::from(0) + Ubig::<8>::from(1), Ubig::<8>::from(1));
121        assert_eq!(Ubig::<8>::from(1) + Ubig::<8>::from(0), Ubig::<8>::from(1));
122        assert_eq!(Ubig::<8>::from(8) + Ubig::<8>::from(9), Ubig::<8>::from(17));
123        assert_eq!(
124            Ubig::<8>::from(usize::MAX) + Ubig::<8>::from(1),
125            unsafe { Ubig::<8>::from_inner_unchecked(smallvec![0, 1]) },
126        );
127    }
128
129    #[test]
130    fn test_add_non_zero() {
131        assert_eq!(
132            NonZeroUbig::<8>::from_str("8").unwrap() + NonZeroUbig::<8>::from_str("9").unwrap(),
133            NonZeroUbig::<8>::from_str("17").unwrap(),
134        );
135        assert_eq!(
136            NonZeroUbig::<8>::from_str("18446744073709551615").unwrap() + NonZeroUbig::<8>::one(),
137            NonZeroUbig::<8>::from_str("18446744073709551616").unwrap(),
138        );
139    }
140
141    #[test]
142    fn test_mul() {
143        assert_eq!(Ubig::<8>::from(0) * Ubig::<8>::from(0), Ubig::<8>::from(0));
144        assert_eq!(Ubig::<8>::from(0) * Ubig::<8>::from(1), Ubig::<8>::from(0));
145        assert_eq!(Ubig::<8>::from(1) * Ubig::<8>::from(0), Ubig::<8>::from(0));
146        assert_eq!(Ubig::<8>::from(8) * Ubig::<8>::from(9), Ubig::<8>::from(72));
147        assert_eq!(
148            Ubig::<8>::from(usize::MAX) * Ubig::<8>::from(1),
149            Ubig::<8>::from(usize::MAX),
150        );
151    }
152
153    #[test]
154    fn test_mul_non_zero() {
155        assert_eq!(
156            NonZeroUbig::<8>::from_str("8").unwrap() * NonZeroUbig::<8>::from_str("9").unwrap(),
157            NonZeroUbig::<8>::from_str("72").unwrap(),
158        );
159        assert_eq!(
160            NonZeroUbig::<8>::from_str("18446744073709551615").unwrap() * NonZeroUbig::<8>::one(),
161            NonZeroUbig::<8>::from_str("18446744073709551615").unwrap(),
162        );
163    }
164}