Skip to main content

bnum/integer/
saturating.rs

1use super::Uint;
2use crate::{Integer, Int};
3use crate::Exponent;
4use crate::doc;
5
6macro_rules! impl_desc {
7    () => {
8        "Saturating arithmetic methods which act on `self`: `self.saturating_...`. For each method, if overflow occurs, the largest or smallest value that can be represented by `Self` is returned instead."
9    };
10}
11
12#[doc = impl_desc!()]
13impl<const S: bool, const N: usize, const B: usize, const OM: u8> Integer<S, N, B, OM> {
14    /// Saturating integer addition. Computes `self + rhs`, returning `Self::MAX` if the result is too large to be represented by `Self`, or `Self::MIN` if the result is too small to be represented by `Self`.
15    /// 
16    /// # Examples
17    /// 
18    /// Basic usage:
19    /// 
20    /// ```
21    /// use bnum::prelude::*;
22    /// use bnum::types::{U1024, I1024};
23    /// 
24    /// assert_eq!(n!(1U1024).saturating_add(n!(1)), n!(2));
25    /// assert_eq!(U1024::MAX.saturating_add(U1024::MAX), U1024::MAX);
26    /// 
27    /// assert_eq!(I1024::MIN.saturating_add(n!(-1)), I1024::MIN);
28    /// assert_eq!(I1024::MAX.saturating_add(n!(1)), I1024::MAX);
29    /// ```
30    #[must_use = doc::must_use_op!()]
31    #[inline]
32    pub const fn saturating_add(self, rhs: Self) -> Self {
33        match self.checked_add(rhs) {
34            Some(add) => add,
35            None => {
36                if self.is_negative_internal() {
37                    Self::MIN
38                } else {
39                    Self::MAX
40                }
41            }
42        }
43    }
44
45    /// Saturating integer subtraction. Computes `self - rhs`, returning `Self::MAX` if the result is too large to be represented by `Self`, or `Self::MIN` if the result is too small to be represented by `Self`.
46    /// 
47    /// # Examples
48    /// 
49    /// Basic usage:
50    /// 
51    /// ```
52    /// use bnum::prelude::*;
53    /// use bnum::types::{U256, I256};
54    /// 
55    /// assert_eq!(n!(1U256).saturating_sub(n!(1)), n!(0));
56    /// assert_eq!(n!(1U256).saturating_sub(n!(2)), n!(0));
57    /// 
58    /// assert_eq!(I256::MIN.saturating_sub(I256::MAX), I256::MIN);
59    /// assert_eq!(I256::MAX.saturating_sub(n!(-1)), I256::MAX);
60    /// ```
61    #[must_use = doc::must_use_op!()]
62    #[inline]
63    pub const fn saturating_sub(self, rhs: Self) -> Self {
64        match self.checked_sub(rhs) {
65            Some(sub) => sub,
66            None => {
67                if rhs.is_negative_internal() {
68                    Self::MAX
69                } else {
70                    Self::MIN
71                }
72            }
73        }
74    }
75
76    /// Saturating integer multiplication. Computes `self * rhs`, returning `Self::MAX` if the result is too large to be represented by `Self`, or `Self::MIN` if the result is too small to be represented by `Self`.
77    /// 
78    /// # Examples
79    /// 
80    /// Basic usage:
81    /// 
82    /// ```
83    /// use bnum::prelude::*;
84    /// use bnum::types::{U1024, I1024};
85    /// 
86    /// assert_eq!(n!(1U1024).saturating_mul(n!(1)), n!(1));
87    /// assert_eq!(U1024::MAX.saturating_mul(n!(2)), U1024::MAX);
88    /// 
89    /// assert_eq!(I1024::MIN.saturating_mul(n!(2)), I1024::MIN);
90    /// assert_eq!(I1024::MAX.saturating_mul(n!(3)), I1024::MAX);
91    /// ```
92    #[must_use = doc::must_use_op!()]
93    #[inline]
94    pub const fn saturating_mul(self, rhs: Self) -> Self {
95        match self.checked_mul(rhs) {
96            Some(mul) => mul,
97            None => {
98                if self.is_negative_internal() == rhs.is_negative_internal() {
99                    Self::MAX
100                } else {
101                    Self::MIN
102                }
103            }
104        }
105    }
106
107    /// Saturating integer division. The only time the result can saturate is if the integer is signed, and `self` is [`Self::MIN`] and `rhs` is `-1`, in which case the result is [`Self::MAX`].
108    /// 
109    /// # Panics
110    /// 
111    /// This function will panic if `rhs` is zero.
112    /// 
113    /// # Examples
114    /// 
115    /// Basic usage:
116    /// 
117    /// ```
118    /// use bnum::prelude::*;
119    /// use bnum::types::I512;
120    /// 
121    /// assert_eq!(n!(5U512).saturating_div(n!(2)), n!(2));
122    /// assert_eq!(I512::MIN.saturating_div(n!(-1)), I512::MAX);
123    /// ```
124    #[must_use = doc::must_use_op!()]
125    #[inline]
126    pub const fn saturating_div(self, rhs: Self) -> Self {
127        let (div, overflow) = self.overflowing_div(rhs);
128        if overflow { Self::MAX } else { div }
129    }
130
131    /// Saturating Euclidean integer division. The only time the result can saturate is if the integer is signed, and `self` is [`Self::MIN`] and `rhs` is `-1`, in which case the result is [`Self::MAX`].
132    /// 
133    /// # Panics
134    /// 
135    /// This function will panic if `rhs` is zero.
136    /// 
137    /// # Examples
138    /// 
139    /// Basic usage:
140    /// 
141    /// ```
142    /// use bnum::prelude::*;
143    /// use bnum::types::I512;
144    /// 
145    /// assert_eq!(n!(19U512).saturating_div_euclid(n!(5)), n!(3));
146    /// assert_eq!(I512::MIN.saturating_div_euclid(n!(-1)), I512::MAX);
147    /// ```
148    #[must_use = doc::must_use_op!()]
149    #[inline]
150    pub const fn saturating_div_euclid(self, rhs: Self) -> Self {
151        let (div, overflow) = self.overflowing_div_euclid(rhs);
152        if overflow { Self::MAX } else { div }
153    }
154
155    // these are not exported from the crate since the Rust primitives do not define them
156    #[must_use = doc::must_use_op!()]
157    #[inline]
158    pub(crate) const fn saturating_rem(self, rhs: Self) -> Self {
159        self.rem(rhs)
160    }
161
162    #[must_use = doc::must_use_op!()]
163    #[inline]
164    pub(crate) const fn saturating_rem_euclid(self, rhs: Self) -> Self {
165        self.rem_euclid(rhs)
166    }
167
168    /// Saturating exponentiation. Computes `self.pow(exp)`, returning `Self::MAX` if the result is too large to be represented by `Self`, or `Self::MIN` if the result is too small to be represented by `Self`.
169    /// 
170    /// # Examples
171    /// 
172    /// Basic usage:
173    /// 
174    /// ```
175    /// use bnum::prelude::*;
176    /// use bnum::types::{U256, I256};
177    /// 
178    /// assert_eq!(n!(2U256).saturating_pow(8), n!(256));
179    /// assert_eq!(n!(2U256).saturating_pow(256), U256::MAX);
180    /// 
181    /// assert_eq!(n!(-2I256).saturating_pow(257), I256::MIN);
182    /// assert_eq!(n!(-2I256).saturating_pow(256), I256::MAX);
183    /// ```
184    #[must_use = doc::must_use_op!()]
185    #[inline]
186    pub const fn saturating_pow(self, exp: Exponent) -> Self {
187        match self.checked_pow(exp) {
188            Some(pow) => pow,
189            None => {
190                if self.is_negative_internal() && exp % 2 != 0 {
191                    Self::MIN
192                } else {
193                    Self::MAX
194                }
195            }
196        }
197    }
198}
199
200#[doc = concat!("(Unsigned integers only.) ", impl_desc!())]
201impl<const N: usize, const B: usize, const OM: u8> Uint<N, B, OM> {
202    #[inline]
203    const fn saturate_up(o: Option<Self>) -> Self {
204        match o {
205            Some(int) => int,
206            None => Self::MAX,
207        }
208    }
209
210    #[inline]
211    const fn saturate_down(o: Option<Self>) -> Self {
212        match o {
213            Some(int) => int,
214            None => Self::MIN,
215        }
216    }
217
218    /// Saturating addition with a signed integer of the same bit width. Computes `self + rhs`, returning `Self::MAX` if the result is too large to be represented by `Self`, or `Self::MIN` if the result is negative.
219    /// 
220    /// # Examples
221    /// 
222    /// Basic usage:
223    /// 
224    /// ```
225    /// use bnum::prelude::*;
226    /// use bnum::types::U512;
227    /// 
228    /// assert_eq!(n!(1U512).saturating_add_signed(n!(-1)), n!(0));
229    /// assert_eq!(U512::MAX.saturating_add_signed(n!(1)), U512::MAX);
230    /// assert_eq!(n!(1U512).saturating_add_signed(n!(-2)), n!(0));
231    /// ```
232    #[must_use = doc::must_use_op!()]
233    #[inline]
234    pub const fn saturating_add_signed(self, rhs: Int<N, B, OM>) -> Self {
235        if rhs.is_negative() {
236            Self::saturate_down(self.checked_add_signed(rhs))
237        } else {
238            Self::saturate_up(self.checked_add_signed(rhs))
239        }
240    }
241
242    /// Saturating subtraction with a signed integer of the same bit width. Computes `self - rhs`, returning `Self::MIN` if the result is negative, or `Self::MAX` if the result is too large to be represented by `Self`.
243    ///
244    /// # Examples
245    /// 
246    /// Basic usage:
247    /// 
248    /// ```
249    /// use bnum::prelude::*;
250    /// use bnum::types::U2048;
251    /// 
252    /// assert_eq!(n!(1U2048).saturating_sub_signed(n!(-1)), n!(2));
253    /// assert_eq!(U2048::MAX.saturating_sub_signed(n!(-4)), U2048::MAX);
254    /// assert_eq!(n!(1U2048).saturating_sub_signed(n!(3)), n!(0));
255    /// ```
256    #[must_use = doc::must_use_op!()]
257    #[inline]
258    pub const fn saturating_sub_signed(self, rhs: Int<N, B, OM>) -> Self
259    {
260        if rhs.is_negative() {
261            Self::saturate_up(self.checked_sub_signed(rhs))
262        } else {
263            Self::saturate_down(self.checked_sub_signed(rhs))
264        }
265    }
266
267    // not exported from the crate since the Rust primitives do not define it
268    #[must_use = doc::must_use_op!()]
269    #[inline]
270    pub(crate) const fn saturating_next_power_of_two(self) -> Self {
271        match self.checked_next_power_of_two() {
272            Some(int) => int,
273            None => Self::MAX,
274        }
275    }
276}
277
278#[doc = concat!("(Signed integers only.) ", impl_desc!())]
279impl<const N: usize, const B: usize, const OM: u8> Int<N, B, OM> {
280    /// Saturating addition with an unsigned integer of the same bit width. Computes `self + rhs`, returning `Self::MAX` if the result is too large to be represented by `Self`.
281    /// 
282    /// # Examples
283    /// 
284    /// Basic usage:
285    /// 
286    /// ```
287    /// use bnum::prelude::*;
288    /// use bnum::types::{I512, U512};
289    /// 
290    /// assert_eq!(n!(-1I512).saturating_add_unsigned(n!(1)), n!(0));
291    /// assert_eq!(n!(0I512).saturating_add_unsigned(U512::MAX), I512::MAX);
292    /// ```
293    #[must_use = doc::must_use_op!()]
294    #[inline]
295    pub const fn saturating_add_unsigned(self, rhs: Uint<N, B, OM>) -> Self {
296        match self.checked_add_unsigned(rhs) {
297            Some(i) => i,
298            None => Self::MAX,
299        }
300    }
301
302    /// Saturating subtraction with an unsigned integer of the same bit width. Computes `self + rhs`, returning `Self::MIN` if the result is too small to be represented by `Self`.
303    /// 
304    /// # Examples
305    /// 
306    /// Basic usage:
307    /// 
308    /// ```
309    /// use bnum::prelude::*;
310    /// use bnum::types::I1024;
311    /// 
312    /// assert_eq!(n!(1I1024).saturating_sub_unsigned(n!(1)), n!(0));
313    /// assert_eq!(I1024::MIN.saturating_sub_unsigned(n!(1)), I1024::MIN);
314    /// ```
315    #[must_use = doc::must_use_op!()]
316    #[inline]
317    pub const fn saturating_sub_unsigned(self, rhs: Uint<N, B, OM>) -> Self {
318        match self.checked_sub_unsigned(rhs) {
319            Some(i) => i,
320            None => Self::MIN,
321        }
322    }
323
324    /// Computes the absolute value of `self`, returning [`Self::MAX`] if the result is too large to be represented by `Self`. The only time this can happen is if `self` is [`Self::MIN`].
325    /// 
326    /// # Examples
327    /// 
328    /// ```
329    /// use bnum::prelude::*;
330    /// use bnum::types::I2048;
331    /// 
332    /// assert_eq!(n!(-7I2048).saturating_abs(), n!(7));
333    /// assert_eq!(n!(22I2048).saturating_abs(), n!(22));
334    /// assert_eq!(I2048::MIN.saturating_abs(), I2048::MAX);
335    /// ```
336    #[must_use = doc::must_use_op!()]
337    #[inline]
338    pub const fn saturating_abs(self) -> Self {
339        match self.checked_abs() {
340            Some(abs) => abs,
341            None => Self::MAX,
342        }
343    }
344
345    /// Saturating negation. Computes `-self`, returning [`Self::MAX`] if the result is too large to be represented by `Self`. The only time this can happen is if `self` is [`Self::MIN`].
346    /// 
347    /// # Examples
348    /// 
349    /// ```
350    /// use bnum::prelude::*;
351    /// use bnum::types::I256;
352    /// 
353    /// assert_eq!(n!(7I256).saturating_neg(), n!(-7));
354    /// assert_eq!(n!(-22I256).saturating_neg(), n!(22));
355    /// assert_eq!(I256::MIN.saturating_neg(), I256::MAX);
356    /// ```
357    #[must_use = doc::must_use_op!()]
358    #[inline]
359    pub const fn saturating_neg(self) -> Self {
360        match self.checked_neg() {
361            Some(abs) => abs,
362            None => Self::MAX,
363        }
364    }
365}
366
367#[cfg(test)]
368mod tests {
369    use crate::test::test_bignum;
370
371    crate::test::test_all! {
372        testing unsigned;
373
374        test_bignum! {
375            function: <utest>::saturating_add_signed(a: utest, b: itest)
376        }
377        test_bignum! {
378            function: <utest>::saturating_sub_signed(a: utest, b: itest)
379        }
380    }
381    crate::test::test_all! {
382        testing signed;
383
384        test_bignum! {
385            function: <itest>::saturating_add_unsigned(a: itest, b: utest)
386        }
387        test_bignum! {
388            function: <itest>::saturating_sub_unsigned(a: itest, b: utest)
389        }
390        test_bignum! {
391            function: <itest>::saturating_neg(a: itest),
392            cases: [
393                (itest::MIN)
394            ]
395        }
396        test_bignum! {
397            function: <itest>::saturating_abs(a: itest),
398            cases: [
399                (itest::MIN)
400            ]
401        }
402    }
403    crate::test::test_all! {
404        testing integers;
405
406        test_bignum! {
407            function: <stest>::saturating_add(a: stest, b: stest)
408        }
409        test_bignum! {
410            function: <stest>::saturating_sub(a: stest, b: stest)
411        }
412        test_bignum! {
413            function: <stest>::saturating_mul(a: stest, b: stest)
414        }
415        test_bignum! {
416            function: <stest>::saturating_div(a: stest, b: stest),
417            skip: b == 0
418        }
419        test_bignum! {
420            function: <stest>::saturating_pow(a: stest, b: u16)
421        }
422    }
423}