relp_num/integer/big/ops/
mod.rs

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