relp_num/integer/big/ops/
mod.rs1use 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 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 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 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 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}