ruint/
add.rs

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    /// Computes the absolute difference between `self` and `other`.
9    ///
10    /// Returns $\left\vert \mathtt{self} - \mathtt{other} \right\vert$.
11    #[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    /// Computes `self + rhs`, returning [`None`] if overflow occurred.
22    #[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    /// Computes `-self`, returning [`None`] unless `self == 0`.
32    #[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    /// Computes `self - rhs`, returning [`None`] if overflow occurred.
42    #[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    /// Calculates $\mod{\mathtt{self} + \mathtt{rhs}}_{2^{BITS}}$.
52    ///
53    /// Returns a tuple of the addition along with a boolean indicating whether
54    /// an arithmetic overflow would occur. If an overflow would have occurred
55    /// then the wrapped value is returned.
56    #[inline]
57    #[must_use]
58    pub const fn overflowing_add(mut self, rhs: Self) -> (Self, bool) {
59        // TODO: Replace with `u64::carrying_add` once stable.
60        #[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    /// Calculates $\mod{-\mathtt{self}}_{2^{BITS}}$.
82    ///
83    /// Returns `!self + 1` using wrapping operations to return the value that
84    /// represents the negation of this unsigned value. Note that for positive
85    /// unsigned values overflow always occurs, but negating 0 does not
86    /// overflow.
87    #[inline(always)]
88    #[must_use]
89    pub const fn overflowing_neg(self) -> (Self, bool) {
90        Self::ZERO.overflowing_sub(self)
91    }
92
93    /// Calculates $\mod{\mathtt{self} - \mathtt{rhs}}_{2^{BITS}}$.
94    ///
95    /// Returns a tuple of the subtraction along with a boolean indicating
96    /// whether an arithmetic overflow would occur. If an overflow would have
97    /// occurred then the wrapped value is returned.
98    #[inline]
99    #[must_use]
100    pub const fn overflowing_sub(mut self, rhs: Self) -> (Self, bool) {
101        // TODO: Replace with `u64::borrowing_sub` once stable.
102        #[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    /// Computes `self + rhs`, saturating at the numeric bounds instead of
124    /// overflowing.
125    #[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    /// Computes `self - rhs`, saturating at the numeric bounds instead of
135    /// overflowing
136    #[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    /// Computes `self + rhs`, wrapping around at the boundary of the type.
146    #[inline(always)]
147    #[must_use]
148    pub const fn wrapping_add(self, rhs: Self) -> Self {
149        self.overflowing_add(rhs).0
150    }
151
152    /// Computes `-self`, wrapping around at the boundary of the type.
153    #[inline(always)]
154    #[must_use]
155    pub const fn wrapping_neg(self) -> Self {
156        self.overflowing_neg().0
157    }
158
159    /// Computes `self - rhs`, wrapping around at the boundary of the type.
160    #[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}