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.masked(), overflow)
73    }
74
75    /// Calculates $\mod{-\mathtt{self}}_{2^{BITS}}$.
76    ///
77    /// Returns `!self + 1` using wrapping operations to return the value that
78    /// represents the negation of this unsigned value. Note that for positive
79    /// unsigned values overflow always occurs, but negating 0 does not
80    /// overflow.
81    #[inline(always)]
82    #[must_use]
83    pub const fn overflowing_neg(self) -> (Self, bool) {
84        Self::ZERO.overflowing_sub(self)
85    }
86
87    /// Calculates $\mod{\mathtt{self} - \mathtt{rhs}}_{2^{BITS}}$.
88    ///
89    /// Returns a tuple of the subtraction along with a boolean indicating
90    /// whether an arithmetic overflow would occur. If an overflow would have
91    /// occurred then the wrapped value is returned.
92    #[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    /// Computes `self + rhs`, saturating at the numeric bounds instead of
109    /// overflowing.
110    #[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    /// Computes `self - rhs`, saturating at the numeric bounds instead of
120    /// overflowing
121    #[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    /// Computes `self + rhs`, wrapping around at the boundary of the type.
131    #[inline(always)]
132    #[must_use]
133    pub const fn wrapping_add(self, rhs: Self) -> Self {
134        self.overflowing_add(rhs).0
135    }
136
137    /// Computes `-self`, wrapping around at the boundary of the type.
138    #[inline(always)]
139    #[must_use]
140    pub const fn wrapping_neg(self) -> Self {
141        self.overflowing_neg().0
142    }
143
144    /// Computes `self - rhs`, wrapping around at the boundary of the type.
145    #[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}