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