1use crate::{
2 algorithms::{borrowing_sub, carrying_add},
3 Uint,
4};
5use core::{
6 iter::Sum,
7 ops::{Add, AddAssign, Neg, Sub, SubAssign},
8};
9
10impl<const BITS: usize, const LIMBS: usize> Uint<BITS, LIMBS> {
11 #[inline(always)]
15 #[must_use]
16 pub fn abs_diff(self, other: Self) -> Self {
17 if self < other {
18 other.wrapping_sub(self)
19 } else {
20 self.wrapping_sub(other)
21 }
22 }
23
24 #[inline(always)]
26 #[must_use]
27 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
28 match self.overflowing_add(rhs) {
29 (value, false) => Some(value),
30 _ => None,
31 }
32 }
33
34 #[inline(always)]
36 #[must_use]
37 pub const fn checked_neg(self) -> Option<Self> {
38 match self.overflowing_neg() {
39 (value, false) => Some(value),
40 _ => None,
41 }
42 }
43
44 #[inline(always)]
46 #[must_use]
47 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
48 match self.overflowing_sub(rhs) {
49 (value, false) => Some(value),
50 _ => None,
51 }
52 }
53
54 #[inline]
60 #[must_use]
61 pub const fn overflowing_add(mut self, rhs: Self) -> (Self, bool) {
62 if BITS == 0 {
63 return (Self::ZERO, false);
64 }
65 let mut carry = false;
66 let mut i = 0;
67 while i < LIMBS {
68 (self.limbs[i], carry) = carrying_add(self.limbs[i], rhs.limbs[i], carry);
69 i += 1;
70 }
71 let overflow = carry | (self.limbs[LIMBS - 1] > Self::MASK);
72 self.limbs[LIMBS - 1] &= Self::MASK;
73 (self, overflow)
74 }
75
76 #[inline(always)]
83 #[must_use]
84 pub const fn overflowing_neg(self) -> (Self, bool) {
85 Self::ZERO.overflowing_sub(self)
86 }
87
88 #[inline]
94 #[must_use]
95 pub const fn overflowing_sub(mut self, rhs: Self) -> (Self, bool) {
96 if BITS == 0 {
97 return (Self::ZERO, false);
98 }
99 let mut borrow = false;
100 let mut i = 0;
101 while i < LIMBS {
102 (self.limbs[i], borrow) = borrowing_sub(self.limbs[i], rhs.limbs[i], borrow);
103 i += 1;
104 }
105 let overflow = borrow | (self.limbs[LIMBS - 1] > Self::MASK);
106 self.limbs[LIMBS - 1] &= Self::MASK;
107 (self, overflow)
108 }
109
110 #[inline(always)]
113 #[must_use]
114 pub const fn saturating_add(self, rhs: Self) -> Self {
115 match self.overflowing_add(rhs) {
116 (value, false) => value,
117 _ => Self::MAX,
118 }
119 }
120
121 #[inline(always)]
124 #[must_use]
125 pub const fn saturating_sub(self, rhs: Self) -> Self {
126 match self.overflowing_sub(rhs) {
127 (value, false) => value,
128 _ => Self::ZERO,
129 }
130 }
131
132 #[inline(always)]
134 #[must_use]
135 pub const fn wrapping_add(self, rhs: Self) -> Self {
136 self.overflowing_add(rhs).0
137 }
138
139 #[inline(always)]
141 #[must_use]
142 pub const fn wrapping_neg(self) -> Self {
143 self.overflowing_neg().0
144 }
145
146 #[inline(always)]
148 #[must_use]
149 pub const fn wrapping_sub(self, rhs: Self) -> Self {
150 self.overflowing_sub(rhs).0
151 }
152}
153
154impl<const BITS: usize, const LIMBS: usize> Neg for Uint<BITS, LIMBS> {
155 type Output = Self;
156
157 #[inline(always)]
158 fn neg(self) -> Self::Output {
159 self.wrapping_neg()
160 }
161}
162
163impl<const BITS: usize, const LIMBS: usize> Neg for &Uint<BITS, LIMBS> {
164 type Output = Uint<BITS, LIMBS>;
165
166 #[inline(always)]
167 fn neg(self) -> Self::Output {
168 self.wrapping_neg()
169 }
170}
171
172impl<const BITS: usize, const LIMBS: usize> Sum<Self> for Uint<BITS, LIMBS> {
173 #[inline]
174 fn sum<I>(iter: I) -> Self
175 where
176 I: Iterator<Item = Self>,
177 {
178 iter.fold(Self::ZERO, Self::wrapping_add)
179 }
180}
181
182impl<'a, const BITS: usize, const LIMBS: usize> Sum<&'a Self> for Uint<BITS, LIMBS> {
183 #[inline]
184 fn sum<I>(iter: I) -> Self
185 where
186 I: Iterator<Item = &'a Self>,
187 {
188 iter.copied().fold(Self::ZERO, Self::wrapping_add)
189 }
190}
191
192impl_bin_op!(Add, add, AddAssign, add_assign, wrapping_add);
193impl_bin_op!(Sub, sub, SubAssign, sub_assign, wrapping_sub);
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198 use crate::{const_for, nlimbs};
199 use proptest::proptest;
200
201 #[test]
202 fn test_neg_one() {
203 const_for!(BITS in NON_ZERO {
204 const LIMBS: usize = nlimbs(BITS);
205 type U = Uint<BITS, LIMBS>;
206 assert_eq!(-U::from(1), !U::ZERO);
207 });
208 }
209
210 #[test]
211 fn test_commutative() {
212 const_for!(BITS in SIZES {
213 const LIMBS: usize = nlimbs(BITS);
214 type U = Uint<BITS, LIMBS>;
215 proptest!(|(a: U, b: U)| {
216 assert_eq!(a + b, b + a);
217 assert_eq!(a - b, -(b - a));
218 });
219 });
220 }
221
222 #[test]
223 fn test_associative() {
224 const_for!(BITS in SIZES {
225 const LIMBS: usize = nlimbs(BITS);
226 type U = Uint<BITS, LIMBS>;
227 proptest!(|(a: U, b: U, c: U)| {
228 assert_eq!(a + (b + c), (a + b) + c);
229 });
230 });
231 }
232
233 #[test]
234 fn test_identity() {
235 const_for!(BITS in SIZES {
236 const LIMBS: usize = nlimbs(BITS);
237 type U = Uint<BITS, LIMBS>;
238 proptest!(|(value: U)| {
239 assert_eq!(value + U::ZERO, value);
240 assert_eq!(value - U::ZERO, value);
241 });
242 });
243 }
244
245 #[test]
246 fn test_inverse() {
247 const_for!(BITS in SIZES {
248 const LIMBS: usize = nlimbs(BITS);
249 type U = Uint<BITS, LIMBS>;
250 proptest!(|(a: U)| {
251 assert_eq!(a + (-a), U::ZERO);
252 assert_eq!(a - a, U::ZERO);
253 assert_eq!(-(-a), a);
254 });
255 });
256 }
257}