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.masked(), overflow)
73 }
74
75 #[inline(always)]
82 #[must_use]
83 pub const fn overflowing_neg(self) -> (Self, bool) {
84 Self::ZERO.overflowing_sub(self)
85 }
86
87 #[inline]
93 #[must_use]
94 pub const fn overflowing_sub(mut self, rhs: Self) -> (Self, bool) {
95 if BITS == 0 {
96 return (Self::ZERO, false);
97 }
98 let mut borrow = false;
99 let mut i = 0;
100 while i < LIMBS {
101 (self.limbs[i], borrow) = borrowing_sub(self.limbs[i], rhs.limbs[i], borrow);
102 i += 1;
103 }
104 let overflow = borrow | (self.limbs[LIMBS - 1] > Self::MASK);
105 (self.masked(), overflow)
106 }
107
108 #[inline(always)]
111 #[must_use]
112 pub const fn saturating_add(self, rhs: Self) -> Self {
113 match self.overflowing_add(rhs) {
114 (value, false) => value,
115 _ => Self::MAX,
116 }
117 }
118
119 #[inline(always)]
122 #[must_use]
123 pub const fn saturating_sub(self, rhs: Self) -> Self {
124 match self.overflowing_sub(rhs) {
125 (value, false) => value,
126 _ => Self::ZERO,
127 }
128 }
129
130 #[inline(always)]
132 #[must_use]
133 pub const fn wrapping_add(self, rhs: Self) -> Self {
134 self.overflowing_add(rhs).0
135 }
136
137 #[inline(always)]
139 #[must_use]
140 pub const fn wrapping_neg(self) -> Self {
141 self.overflowing_neg().0
142 }
143
144 #[inline(always)]
146 #[must_use]
147 pub const fn wrapping_sub(self, rhs: Self) -> Self {
148 self.overflowing_sub(rhs).0
149 }
150}
151
152impl<const BITS: usize, const LIMBS: usize> Neg for Uint<BITS, LIMBS> {
153 type Output = Self;
154
155 #[inline(always)]
156 fn neg(self) -> Self::Output {
157 self.wrapping_neg()
158 }
159}
160
161impl<const BITS: usize, const LIMBS: usize> Neg for &Uint<BITS, LIMBS> {
162 type Output = Uint<BITS, LIMBS>;
163
164 #[inline(always)]
165 fn neg(self) -> Self::Output {
166 self.wrapping_neg()
167 }
168}
169
170impl<const BITS: usize, const LIMBS: usize> Sum<Self> for Uint<BITS, LIMBS> {
171 #[inline]
172 fn sum<I>(iter: I) -> Self
173 where
174 I: Iterator<Item = Self>,
175 {
176 iter.fold(Self::ZERO, Self::wrapping_add)
177 }
178}
179
180impl<'a, const BITS: usize, const LIMBS: usize> Sum<&'a Self> for Uint<BITS, LIMBS> {
181 #[inline]
182 fn sum<I>(iter: I) -> Self
183 where
184 I: Iterator<Item = &'a Self>,
185 {
186 iter.copied().fold(Self::ZERO, Self::wrapping_add)
187 }
188}
189
190impl_bin_op!(Add, add, AddAssign, add_assign, wrapping_add);
191impl_bin_op!(Sub, sub, SubAssign, sub_assign, wrapping_sub);
192
193#[cfg(test)]
194mod tests {
195 use super::*;
196 use crate::{const_for, nlimbs};
197 use proptest::proptest;
198
199 #[test]
200 fn test_neg_one() {
201 const_for!(BITS in NON_ZERO {
202 const LIMBS: usize = nlimbs(BITS);
203 type U = Uint<BITS, LIMBS>;
204 assert_eq!(-U::ONE, !U::ZERO);
205 });
206 }
207
208 #[test]
209 fn test_commutative() {
210 const_for!(BITS in SIZES {
211 const LIMBS: usize = nlimbs(BITS);
212 type U = Uint<BITS, LIMBS>;
213 proptest!(|(a: U, b: U)| {
214 assert_eq!(a + b, b + a);
215 assert_eq!(a - b, -(b - a));
216 });
217 });
218 }
219
220 #[test]
221 fn test_associative() {
222 const_for!(BITS in SIZES {
223 const LIMBS: usize = nlimbs(BITS);
224 type U = Uint<BITS, LIMBS>;
225 proptest!(|(a: U, b: U, c: U)| {
226 assert_eq!(a + (b + c), (a + b) + c);
227 });
228 });
229 }
230
231 #[test]
232 fn test_identity() {
233 const_for!(BITS in SIZES {
234 const LIMBS: usize = nlimbs(BITS);
235 type U = Uint<BITS, LIMBS>;
236 proptest!(|(value: U)| {
237 assert_eq!(value + U::ZERO, value);
238 assert_eq!(value - U::ZERO, value);
239 });
240 });
241 }
242
243 #[test]
244 fn test_inverse() {
245 const_for!(BITS in SIZES {
246 const LIMBS: usize = nlimbs(BITS);
247 type U = Uint<BITS, LIMBS>;
248 proptest!(|(a: U)| {
249 assert_eq!(a + (-a), U::ZERO);
250 assert_eq!(a - a, U::ZERO);
251 assert_eq!(-(-a), a);
252 });
253 });
254 }
255}