ruint/
add.rs

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    /// Computes the absolute difference between `self` and `other`.
12    ///
13    /// Returns $\left\vert \mathtt{self} - \mathtt{other} \right\vert$.
14    #[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    /// Computes `self + rhs`, returning [`None`] if overflow occurred.
25    #[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    /// Computes `-self`, returning [`None`] unless `self == 0`.
35    #[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    /// Computes `self - rhs`, returning [`None`] if overflow occurred.
45    #[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    /// Calculates $\mod{\mathtt{self} + \mathtt{rhs}}_{2^{BITS}}$.
55    ///
56    /// Returns a tuple of the addition along with a boolean indicating whether
57    /// an arithmetic overflow would occur. If an overflow would have occurred
58    /// then the wrapped value is returned.
59    #[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    /// Calculates $\mod{-\mathtt{self}}_{2^{BITS}}$.
77    ///
78    /// Returns `!self + 1` using wrapping operations to return the value that
79    /// represents the negation of this unsigned value. Note that for positive
80    /// unsigned values overflow always occurs, but negating 0 does not
81    /// overflow.
82    #[inline(always)]
83    #[must_use]
84    pub const fn overflowing_neg(self) -> (Self, bool) {
85        Self::ZERO.overflowing_sub(self)
86    }
87
88    /// Calculates $\mod{\mathtt{self} - \mathtt{rhs}}_{2^{BITS}}$.
89    ///
90    /// Returns a tuple of the subtraction along with a boolean indicating
91    /// whether an arithmetic overflow would occur. If an overflow would have
92    /// occurred then the wrapped value is returned.
93    #[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    /// Computes `self + rhs`, saturating at the numeric bounds instead of
111    /// overflowing.
112    #[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    /// Computes `self - rhs`, saturating at the numeric bounds instead of
122    /// overflowing
123    #[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    /// Computes `self + rhs`, wrapping around at the boundary of the type.
133    #[inline(always)]
134    #[must_use]
135    pub const fn wrapping_add(self, rhs: Self) -> Self {
136        self.overflowing_add(rhs).0
137    }
138
139    /// Computes `-self`, wrapping around at the boundary of the type.
140    #[inline(always)]
141    #[must_use]
142    pub const fn wrapping_neg(self) -> Self {
143        self.overflowing_neg().0
144    }
145
146    /// Computes `self - rhs`, wrapping around at the boundary of the type.
147    #[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}