1use crate::digit;
2use crate::doc;
3use crate::errors::div_zero;
4use crate::helpers::tuple_to_option;
5use crate::ExpType;
6
7macro_rules! checked {
8 ($BUint: ident, $BInt: ident, $Digit: ident) => {
9 #[doc = doc::checked::impl_desc!()]
10 impl<const N: usize> $BUint<N> {
11 #[doc = doc::checked::checked_add!(U)]
12 #[must_use = doc::must_use_op!()]
13 #[inline]
14 pub const fn checked_add(self, rhs: Self) -> Option<Self> {
15 tuple_to_option(self.overflowing_add(rhs))
16 }
17
18 #[doc = doc::checked::checked_add_signed!(U)]
19 #[must_use = doc::must_use_op!()]
20 #[inline]
21 pub const fn checked_add_signed(self, rhs: $BInt<N>) -> Option<Self> {
22 tuple_to_option(self.overflowing_add_signed(rhs))
23 }
24
25 #[doc = doc::checked::checked_sub!(U)]
26 #[must_use = doc::must_use_op!()]
27 #[inline]
28 pub const fn checked_sub(self, rhs: Self) -> Option<Self> {
29 tuple_to_option(self.overflowing_sub(rhs))
30 }
31
32 #[doc = doc::checked::checked_mul!(U)]
33 #[must_use = doc::must_use_op!()]
34 #[inline]
35 pub const fn checked_mul(self, rhs: Self) -> Option<Self> {
36 tuple_to_option(self.overflowing_mul(rhs))
37 }
38
39 pub(crate) const fn div_rem_digit(self, rhs: $Digit) -> (Self, $Digit) {
40 let mut out = Self::ZERO;
41 let mut rem: $Digit = 0;
42 let mut i = N;
43 while i > 0 {
44 i -= 1;
45 let (q, r) = digit::$Digit::div_rem_wide(self.digits[i], rem, rhs);
46 rem = r;
47 out.digits[i] = q;
48 }
49 (out, rem)
50 }
51
52
53 #[inline]
54 pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) {
55 use core::cmp::Ordering;
56
57 if self.is_zero() {
58 return (Self::ZERO, Self::ZERO);
59 }
60
61 match self.cmp(&rhs) {
62 Ordering::Less => (Self::ZERO, self),
63 Ordering::Equal => (Self::ONE, Self::ZERO),
64 Ordering::Greater => {
65 let ldi = rhs.last_digit_index();
66 if ldi == 0 {
67 let (div, rem) = self.div_rem_digit(rhs.digits[0]);
68 (div, Self::from_digit(rem))
69 } else {
70 self.basecase_div_rem(rhs, ldi + 1)
71 }
72 }
73 }
74 }
75
76 #[inline]
77 pub(crate) const fn div_rem(self, rhs: Self) -> (Self, Self) {
78 if rhs.is_zero() {
79 div_zero!()
80 } else {
81 self.div_rem_unchecked(rhs)
82 }
83 }
84
85 #[doc = doc::checked::checked_div!(U)]
86 #[must_use = doc::must_use_op!()]
87 #[inline]
88 pub const fn checked_div(self, rhs: Self) -> Option<Self> {
89 if rhs.is_zero() {
90 None
91 } else {
92 Some(self.div_rem_unchecked(rhs).0)
93 }
94 }
95
96 #[doc = doc::checked::checked_div_euclid!(U)]
97 #[must_use = doc::must_use_op!()]
98 #[inline]
99 pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
100 self.checked_div(rhs)
101 }
102
103 #[doc = doc::checked::checked_rem!(U)]
104 #[must_use = doc::must_use_op!()]
105 #[inline]
106 pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
107 if rhs.is_zero() {
108 None
109 } else {
110 Some(self.div_rem_unchecked(rhs).1)
111 }
112 }
113
114 #[doc = doc::checked::checked_rem_euclid!(U)]
115 #[must_use = doc::must_use_op!()]
116 #[inline]
117 pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
118 self.checked_rem(rhs)
119 }
120
121 #[doc = doc::checked::checked_neg!(U)]
122 #[must_use = doc::must_use_op!()]
123 #[inline]
124 pub const fn checked_neg(self) -> Option<Self> {
125 if self.is_zero() {
126 Some(self)
127 } else {
128 None
129 }
130 }
131
132 #[doc = doc::checked::checked_shl!(U)]
133 #[must_use = doc::must_use_op!()]
134 #[inline]
135 pub const fn checked_shl(self, rhs: ExpType) -> Option<Self> {
136 if rhs >= Self::BITS {
137 None
138 } else {
139 unsafe {
140 Some(Self::unchecked_shl_internal(self, rhs))
141 }
142 }
143 }
144
145 #[doc = doc::checked::checked_shr!(U)]
146 #[must_use = doc::must_use_op!()]
147 #[inline]
148 pub const fn checked_shr(self, rhs: ExpType) -> Option<Self> {
149 if rhs >= Self::BITS {
150 None
151 } else {
152 unsafe {
153 Some(Self::unchecked_shr_internal(self, rhs))
154 }
155 }
156 }
157
158 #[doc = doc::checked::checked_pow!(U)]
159 #[must_use = doc::must_use_op!()]
160 #[inline]
161 pub const fn checked_pow(mut self, mut pow: ExpType) -> Option<Self> {
162 if pow == 0 {
164 return Some(Self::ONE);
165 }
166 let mut y = Self::ONE;
167 while pow > 1 {
168 if pow & 1 == 1 {
169 y = match self.checked_mul(y) {
170 Some(m) => m,
171 None => return None,
172 };
173 }
174 self = match self.checked_mul(self) {
175 Some(m) => m,
176 None => return None,
177 };
178 pow >>= 1;
179 }
180 self.checked_mul(y)
181 }
182
183 #[doc = doc::checked::checked_next_multiple_of!(U)]
184 #[must_use = doc::must_use_op!()]
185 #[inline]
186 pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
187 match self.checked_rem(rhs) {
188 Some(rem) => {
189 if rem.is_zero() {
190 Some(self)
192 } else {
193 self.checked_add(rhs.sub(rem))
195 }
196 },
197 None => None,
198 }
199 }
200
201 #[doc = doc::checked::checked_ilog2!(U)]
202 #[must_use = doc::must_use_op!()]
203 #[inline]
204 pub const fn checked_ilog2(self) -> Option<ExpType> {
205 self.bits().checked_sub(1)
206 }
207
208 #[inline]
209 const fn iilog(m: ExpType, b: Self, k: Self) -> (ExpType, Self) {
210 if b.gt(&k) {
212 (m, k)
213 } else {
214 let (new, q) = Self::iilog(m << 1, b.mul(b), k.div_rem_unchecked(b).0);
215 if b.gt(&q) {
216 (new, q)
217 } else {
218 (new + m, q.div(b))
219 }
220 }
221 }
222
223 #[doc = doc::checked::checked_ilog10!(U)]
224 #[must_use = doc::must_use_op!()]
225 #[inline]
226 pub const fn checked_ilog10(self) -> Option<ExpType> {
227 if self.is_zero() {
228 return None;
229 }
230 if Self::TEN.gt(&self) {
231 return Some(0);
232 }
233 Some(Self::iilog(1, Self::TEN, self.div_rem_digit(10).0).0)
234 }
235
236 #[doc = doc::checked::checked_ilog!(U)]
237 #[must_use = doc::must_use_op!()]
238 #[inline]
239 pub const fn checked_ilog(self, base: Self) -> Option<ExpType> {
240 use core::cmp::Ordering;
241 match base.cmp(&Self::TWO) {
242 Ordering::Less => None,
243 Ordering::Equal => self.checked_ilog2(),
244 Ordering::Greater => {
245 if self.is_zero() {
246 return None;
247 }
248 if base.gt(&self) {
249 return Some(0);
250 }
251 Some(Self::iilog(1, base, self.div(base)).0)
252 }
253 }
254 }
255
256 #[doc = doc::checked::checked_next_power_of_two!(U 256)]
257 #[must_use = doc::must_use_op!()]
258 #[inline]
259 pub const fn checked_next_power_of_two(self) -> Option<Self> {
260 if self.is_power_of_two() {
261 return Some(self);
262 }
263 let bits = self.bits();
264 if bits == Self::BITS {
265 return None;
266 }
267 Some(Self::power_of_two(bits))
268 }
269 }
270 };
271}
272
273#[cfg(test)]
274crate::test::all_digit_tests! {
275 use crate::test::{test_bignum, types::*};
276
277 test_bignum! {
278 function: <utest>::checked_add(a: utest, b: utest),
279 cases: [
280 (utest::MAX, 1u8)
281 ]
282 }
283 test_bignum! {
284 function: <utest>::checked_add_signed(a: utest, b: itest)
285 }
286 test_bignum! {
287 function: <utest>::checked_sub(a: utest, b: utest)
288 }
289 test_bignum! {
290 function: <utest>::checked_mul(a: utest, b: utest)
291 }
292 test_bignum! {
293 function: <utest>::checked_div(a: utest, b: utest),
294 cases: [
295 (328622u32 as utest, 10000u32 as utest), (2074086u32 as utest, 76819u32 as utest) ]
298 }
299 test_bignum! {
300 function: <utest>::checked_div_euclid(a: utest, b: utest)
301 }
302 test_bignum! {
303 function: <utest>::checked_rem(a: utest, b: utest)
304 }
305 test_bignum! {
306 function: <utest>::checked_rem_euclid(a: utest, b: utest)
307 }
308 test_bignum! {
309 function: <utest>::checked_neg(a: utest)
310 }
311 test_bignum! {
312 function: <utest>::checked_shl(a: utest, b: u16)
313 }
314 test_bignum! {
315 function: <utest>::checked_shr(a: utest, b: u16)
316 }
317 test_bignum! {
318 function: <utest>::checked_pow(a: utest, b: u16)
319 }
320 test_bignum! {
321 function: <utest>::checked_ilog(a: utest, b: utest),
322 cases: [
323 (2u8, 60u8),
324 (utest::MAX, 2u8)
325 ]
326 }
327 test_bignum! {
328 function: <utest>::checked_ilog2(a: utest)
329 }
330 test_bignum! {
331 function: <utest>::checked_ilog10(a: utest)
332 }
333 test_bignum! {
334 function: <utest>::checked_next_power_of_two(a: utest),
335 cases: [
336 (utest::MAX)
337 ]
338 }
339}
340
341crate::macro_impl!(checked);