relp_num/integer/big/ops/
mod.rs1use 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::non_zero::{add_assign, mul_non_zero};
8
9pub(crate) mod building_blocks;
10pub mod non_zero;
11pub mod div;
12pub mod normalize;
13#[cfg(test)]
14mod normalize_bench;
15
16
17impl<const S: usize> Add for Ubig<S> {
18 type Output = Self;
19
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 left += &right;
33
34 left
35 }
36}
37
38
39impl<const S: usize> Add for NonZeroUbig<S> {
40 type Output = Self;
41
42 #[inline]
43 fn add(self, rhs: Self) -> Self::Output {
44 let (mut left, right) = if rhs.0.len() > self.0.len() {
45 (rhs, self)
46 } else {
47 (self, rhs)
48 };
49
50 left += &right;
51
52 left
53 }
54}
55
56
57impl<const S: usize> AddAssign<&Self> for Ubig<S> {
58 #[inline]
59 fn add_assign(&mut self, rhs: &Ubig<S>) {
60 add_assign(&mut self.0, &rhs.0);
61 }
62}
63
64impl<const S: usize> AddAssign<&Self> for NonZeroUbig<S> {
65 #[inline]
66 fn add_assign(&mut self, rhs: &Self) {
67 unsafe {
68 assert_unchecked(!self.0.is_empty());
70 assert_unchecked(!rhs.0.is_empty());
71 }
72 add_assign(&mut self.0, &rhs.0);
73 }
74}
75
76impl<const S: usize> Mul for Ubig<S> {
77 type Output = Self;
78
79 fn mul(mut self, rhs: Self) -> Self::Output {
80 if !self.is_zero() && !rhs.is_zero() {
81 unsafe {
82 Self(mul_non_zero(&self.0, &rhs.0))
84 }
85 } else {
86 self.set_zero();
87 self
88 }
89 }
90}
91
92impl<const S: usize> Mul for NonZeroUbig<S> {
93 type Output = Self;
94
95 fn mul(self, rhs: Self) -> Self::Output {
96 unsafe {
97 Self(mul_non_zero(&self.0, &rhs.0))
99 }
100 }
101}
102
103#[cfg(test)]
104mod test {
105 use std::str::FromStr;
106
107 use num_traits::One;
108 use smallvec::smallvec;
109
110 use crate::{NonZeroUbig, Ubig};
111
112 #[test]
113 fn test_add() {
114 assert_eq!(Ubig::<8>::from(0_usize) + Ubig::<8>::from(0_usize), Ubig::<8>::from(0_usize));
115 assert_eq!(Ubig::<8>::from(0_usize) + Ubig::<8>::from(1_usize), Ubig::<8>::from(1_usize));
116 assert_eq!(Ubig::<8>::from(1_usize) + Ubig::<8>::from(0_usize), Ubig::<8>::from(1_usize));
117 assert_eq!(Ubig::<8>::from(8_usize) + Ubig::<8>::from(9_usize), Ubig::<8>::from(17_usize));
118 assert_eq!(
119 Ubig::<8>::from(usize::MAX) + Ubig::<8>::from(1_usize),
120 unsafe { Ubig::<8>::from_inner_unchecked(smallvec![0, 1]) },
121 );
122 }
123
124 #[test]
125 fn test_add_unequal_lengths() {
126 let one = Ubig::<8>::from(1_usize);
130
131 let large = Ubig::<8>::from_str("18446744073709551616").unwrap(); let expected = Ubig::<8>::from_str("18446744073709551617").unwrap();
133 assert_eq!(one.clone() + large.clone(), expected);
134 assert_eq!(large + one.clone(), expected);
135
136 let left = unsafe { Ubig::<8>::from_inner_unchecked(smallvec![usize::MAX, 5]) };
138 let expected = unsafe { Ubig::<8>::from_inner_unchecked(smallvec![0, 6]) };
139 assert_eq!(left.clone() + one.clone(), expected);
140 assert_eq!(one.clone() + left, expected);
141
142 let left = unsafe {
144 Ubig::<8>::from_inner_unchecked(smallvec![usize::MAX, usize::MAX, usize::MAX, 5])
145 };
146 let expected = unsafe { Ubig::<8>::from_inner_unchecked(smallvec![0, 0, 0, 6]) };
147 assert_eq!(left.clone() + one.clone(), expected);
148 assert_eq!(one.clone() + left, expected);
149
150 let left = unsafe {
152 Ubig::<8>::from_inner_unchecked(smallvec![usize::MAX, usize::MAX, usize::MAX])
153 };
154 let expected = unsafe { Ubig::<8>::from_inner_unchecked(smallvec![0, 0, 0, 1]) };
155 assert_eq!(left.clone() + one.clone(), expected);
156 assert_eq!(one.clone() + left, expected);
157
158 let left = unsafe { Ubig::<8>::from_inner_unchecked(smallvec![1, 2, 3]) };
160 let right = unsafe { Ubig::<8>::from_inner_unchecked(smallvec![10, 20]) };
161 let expected = unsafe { Ubig::<8>::from_inner_unchecked(smallvec![11, 22, 3]) };
162 assert_eq!(left.clone() + right.clone(), expected);
163 assert_eq!(right + left, expected);
164 }
165
166 #[test]
167 fn test_add_non_zero_unequal_lengths() {
168 let one = NonZeroUbig::<8>::one();
169
170 let large = NonZeroUbig::<8>::from_str("18446744073709551616").unwrap(); let expected = NonZeroUbig::<8>::from_str("18446744073709551617").unwrap();
172 assert_eq!(one.clone() + large.clone(), expected);
173 assert_eq!(large + one.clone(), expected);
174
175 let left = unsafe { NonZeroUbig::<8>::from_inner_unchecked(smallvec![usize::MAX, 5]) };
177 let expected = unsafe { NonZeroUbig::<8>::from_inner_unchecked(smallvec![0, 6]) };
178 assert_eq!(left.clone() + one.clone(), expected);
179 assert_eq!(one.clone() + left, expected);
180
181 let left = unsafe {
182 NonZeroUbig::<8>::from_inner_unchecked(smallvec![usize::MAX, usize::MAX, usize::MAX, 5])
183 };
184 let expected = unsafe { NonZeroUbig::<8>::from_inner_unchecked(smallvec![0, 0, 0, 6]) };
185 assert_eq!(left.clone() + one.clone(), expected);
186 assert_eq!(one + left, expected);
187 }
188
189 #[test]
190 fn test_add_non_zero() {
191 assert_eq!(
192 NonZeroUbig::<8>::from_str("8").unwrap() + NonZeroUbig::<8>::from_str("9").unwrap(),
193 NonZeroUbig::<8>::from_str("17").unwrap(),
194 );
195 assert_eq!(
196 NonZeroUbig::<8>::from_str("18446744073709551615").unwrap() + NonZeroUbig::<8>::one(),
197 NonZeroUbig::<8>::from_str("18446744073709551616").unwrap(),
198 );
199 }
200
201 #[test]
202 fn test_mul() {
203 assert_eq!(Ubig::<8>::from(0_usize) * Ubig::<8>::from(0_usize), Ubig::<8>::from(0_usize));
204 assert_eq!(Ubig::<8>::from(0_usize) * Ubig::<8>::from(1_usize), Ubig::<8>::from(0_usize));
205 assert_eq!(Ubig::<8>::from(1_usize) * Ubig::<8>::from(0_usize), Ubig::<8>::from(0_usize));
206 assert_eq!(Ubig::<8>::from(8_usize) * Ubig::<8>::from(9_usize), Ubig::<8>::from(72_usize));
207 assert_eq!(
208 Ubig::<8>::from(usize::MAX) * Ubig::<8>::from(1_usize),
209 Ubig::<8>::from(usize::MAX),
210 );
211 }
212
213 #[test]
214 fn test_mul_non_zero() {
215 assert_eq!(
216 NonZeroUbig::<8>::from_str("8").unwrap() * NonZeroUbig::<8>::from_str("9").unwrap(),
217 NonZeroUbig::<8>::from_str("72").unwrap(),
218 );
219 assert_eq!(
220 NonZeroUbig::<8>::from_str("18446744073709551615").unwrap() * NonZeroUbig::<8>::one(),
221 NonZeroUbig::<8>::from_str("18446744073709551615").unwrap(),
222 );
223 }
224}