i256/uint/
checked.rs

1//! Arithematic operations which only return a value if no overflow occurs.
2
3#[rustfmt::skip]
4macro_rules! define {
5    (
6        signed_type => $s_t:ty,
7        wide_type => $wide_t:ty,
8        see_type => $see_t:ty $(,)?
9    ) => {
10        $crate::shared::checked::define!(
11            type => $s_t,
12            wide_type => $wide_t,
13            see_type => $see_t,
14        );
15
16        /// Checked addition with a signed integer. Computes `self + rhs`,
17        /// returning `None` if overflow occurred.
18        #[doc = $crate::shared::docs::primitive_doc!($see_t, checked_add_signed)]
19        #[inline(always)]
20        #[must_use = $crate::shared::docs::must_use_copy_doc!()]
21        pub const fn checked_add_signed(self, rhs: $s_t) -> Option<Self> {
22            let (value, overflowed) = self.overflowing_add_signed(rhs);
23            if !overflowed {
24                Some(value)
25            } else {
26                None
27            }
28        }
29
30        /// Checked negation. Computes `-self`, returning `None` unless `self ==
31        /// 0`.
32        ///
33        /// Note that negating any positive integer will overflow.
34        #[doc = $crate::shared::docs::primitive_doc!($see_t, checked_neg)]
35        #[inline(always)]
36        #[must_use = $crate::shared::docs::must_use_copy_doc!()]
37        pub const fn checked_neg(self) -> Option<Self> {
38            if self.eq_const(Self::MIN) {
39                Some(self)
40            } else {
41                None
42            }
43        }
44
45        /// Returns the logarithm of the number with respect to an arbitrary base,
46        /// rounded down.
47        ///
48        /// Returns `None` if the number is zero, or if the base is not at least 2.
49        ///
50        /// This method might not be optimized owing to implementation details;
51        /// `checked_ilog2` can produce results more efficiently for base 2, and
52        /// `checked_ilog10` can produce results more efficiently for base 10.
53        #[doc = $crate::shared::docs::primitive_doc!($see_t, checked_ilog)]
54        #[inline(always)]
55        pub fn checked_ilog(self, base: Self) -> Option<u32> {
56            let zero = Self::from_u8(0);
57            if self == zero || base <= zero || self < base {
58                return None;
59            }
60
61            // Since base >= self, n >= 1
62            let mut n = 1;
63            let mut r = base;
64
65            // Optimization for 128+ bit wide integers.
66            if Self::BITS >= $crate::UWide::BITS {
67                // The following is a correct lower bound for ⌊log(base,self)⌋ because
68                //
69                // log(base,self) = log(2,self) / log(2,base)
70                //                ≥ ⌊log(2,self)⌋ / (⌊log(2,base)⌋ + 1)
71                //
72                // hence
73                //
74                // ⌊log(base,self)⌋ ≥ ⌊ ⌊log(2,self)⌋ / (⌊log(2,base)⌋ + 1) ⌋ .
75                n = self.ilog2() / (base.ilog2() + 1);
76                r = base.pow(n);
77            }
78
79            while r <= self / base {
80                n += 1;
81                r *= base;
82            }
83            Some(n)
84        }
85
86        // FIXME: Stabilize when our MSRV goes to `1.67.0+`.
87        // /// Returns the base 10 logarithm of the number, rounded down.
88        // ///
89        // /// Returns `None` if the number is zero.
90        // #[inline(always)]
91        // pub fn checked_ilog10(self) -> Option<u32> {
92        //     match self.eq_const(Self::from_u8(0)) {
93        //         true => None,
94        //         false => {
95        //             // NOTE: The `ilog10` implementations for small
96        //             // numbers are quite efficient, so we use those
97        //             // when available. We want to get this to
98        //             // a 128-bit integer in as few multiplications
99        //             // as we can.
100        //             let mut log = 0;
101        //             let mut value = self;
102        //             const E16: u64 = 10_000_000_000_000_000;
103        //             while value.high() > 0 {
104        //                 value = value.div_wide(E16);
105        //                 log += 16;
106        //             }
107        //             let value: u128 = value.as_u128();
108        //             Some(value.ilog10() + log)
109        //         },
110        //     }
111        // }
112
113        /// Calculates the smallest value greater than or equal to `self` that
114        /// is a multiple of `rhs`. Returns `None` if `rhs` is zero or the
115        /// operation would result in overflow.
116        #[doc = $crate::shared::docs::primitive_doc!($see_t, checked_next_multiple_of)]
117        #[inline]
118        #[must_use = $crate::shared::docs::must_use_copy_doc!()]
119        pub fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
120            match self.checked_rem(rhs) {
121                None => None,
122                Some(Self::MIN) => Some(self),
123                // rhs - r cannot overflow because r is smaller than rhs
124                Some(r) => self.checked_add(rhs.wrapping_sub(r)),
125            }
126        }
127
128        /// Checked subtraction with a signed integer. Computes `self - rhs`,
129        /// returning `None` if overflow occurred.
130        #[inline]
131        #[must_use = $crate::shared::docs::must_use_copy_doc!()]
132        pub const fn checked_signed_diff(self, rhs: Self) -> Option<$s_t> {
133            let res = self.wrapping_sub(rhs).as_signed();
134            let overflow = self.ge_const(rhs) == res.lt_const(<$s_t>::from_u8(0));
135
136            if !overflow {
137                Some(res)
138            } else {
139                None
140            }
141        }
142
143        /// Returns the smallest power of two greater than or equal to `self`. If
144        /// the next power of two is greater than the type's maximum value,
145        /// `None` is returned, otherwise the power of two is wrapped in `Some`.
146        #[doc = $crate::shared::docs::primitive_doc!($see_t, checked_next_power_of_two)]
147        #[inline]
148        #[must_use = $crate::shared::docs::must_use_copy_doc!()]
149        pub const fn checked_next_power_of_two(self) -> Option<Self> {
150            self.one_less_than_next_power_of_two().checked_add(Self::from_u8(1))
151        }
152    };
153}
154
155pub(crate) use define;