reweb3_num/buint/
checked.rs

1use crate::digit;
2use crate::doc;
3use crate::errors::div_zero;
4use crate::int::checked::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            const fn basecase_div_rem(self, mut v: Self, n: usize) -> (Self, Self) {
52                // The Art of Computer Programming Volume 2 by Donald Knuth, Section 4.3.1, Algorithm D
53
54                let mut q = Self::ZERO;
55                let m = self.last_digit_index() + 1 - n;
56                let shift = v.digits[n - 1].leading_zeros() as ExpType;
57
58                v = unsafe { Self::unchecked_shl_internal(v, shift) }; // D1
59
60                struct Remainder<const M: usize> {
61                    first: $Digit,
62                    rest: [$Digit; M],
63                }
64                impl<const M: usize> Remainder<M> {
65                    const fn digit(&self, index: usize) -> $Digit {
66                        if index == 0 {
67                            self.first
68                        } else {
69                            self.rest[index - 1]
70                        }
71                    }
72                    const fn shr(self, shift: ExpType) -> $BUint<M> {
73                        let mut out = $BUint::ZERO;
74                        let mut i = 0;
75                        while i < M {
76                            out.digits[i] = self.digit(i) >> shift;
77                            i += 1;
78                        }
79                        if shift > 0 {
80                            i = 0;
81                            while i < M {
82                                out.digits[i] |=
83                                    self.rest[i] << (digit::$Digit::BITS as ExpType - shift);
84                                i += 1;
85                            }
86                        }
87                        out
88                    }
89                    const fn new(uint: $BUint<M>, shift: ExpType) -> Self {
90                        let first = uint.digits[0] << shift;
91                        let rest = uint.wrapping_shr(digit::$Digit::BITS - shift);
92                        Self {
93                            first,
94                            rest: rest.digits,
95                        }
96                    }
97                    /*crate::nightly::const_fns! {
98                        const fn set_digit(&mut self, index: usize, digit: $Digit) -> () {
99                            if index == 0 {
100                                self.first = digit;
101                            } else {
102                                self.rest[index - 1] = digit;
103                            }
104                        }
105                        const fn sub(&mut self, rhs: Mul<M>, start: usize, range: usize) -> bool {
106                            let mut borrow = false;
107                            let mut i = 0;
108                            while i <= range {
109                                let (sub, overflow) = digit::$Digit::borrowing_sub(self.digit(i + start), rhs.digit(i), borrow);
110                                self.set_digit(i + start, sub);
111                                borrow = overflow;
112                                i += 1;
113                            }
114                            borrow
115                        }
116                        const fn add(&mut self, rhs: $BUint<M>, start: usize, range: usize) -> () {
117                            let mut carry = false;
118                            let mut i = 0;
119                            while i < range {
120                                let (sum, overflow) = digit::$Digit::carrying_add(self.digit(i + start), rhs.digits[i], carry);
121                                self.set_digit(i + start, sum);
122                                carry = overflow;
123                                i += 1;
124                            }
125                            if carry {
126                                self.set_digit(range + start, self.digit(range + start).wrapping_add(1)); // we use wrapping_add here, not regular addition as a carry will always occur to the left of self.digit(range + start)
127                            }
128                        }
129                    }*/
130                    const fn sub(
131                        mut self,
132                        rhs: Mul<M>,
133                        start: usize,
134                        range: usize,
135                    ) -> (Self, bool) {
136                        let mut borrow = false;
137                        let mut i = 0;
138                        while i <= range {
139                            let (sub, overflow) = digit::$Digit::borrowing_sub(
140                                self.digit(i + start),
141                                rhs.digit(i),
142                                borrow,
143                            );
144                            if start == 0 && i == 0 {
145                                self.first = sub;
146                            } else {
147                                self.rest[i + start - 1] = sub;
148                            }
149                            borrow = overflow;
150                            i += 1;
151                        }
152                        (self, borrow)
153                    }
154                    const fn add(mut self, rhs: $BUint<M>, start: usize, range: usize) -> Self {
155                        let mut carry = false;
156                        let mut i = 0;
157                        while i < range {
158                            let (sum, overflow) = digit::$Digit::carrying_add(
159                                self.digit(i + start),
160                                rhs.digits[i],
161                                carry,
162                            );
163                            if start == 0 && i == 0 {
164                                self.first = sum;
165                            } else {
166                                self.rest[i + start - 1] = sum;
167                            }
168                            carry = overflow;
169                            i += 1;
170                        }
171                        if carry {
172                            if start == 0 && range == 0 {
173                                self.first = self.first.wrapping_add(1);
174                            } else {
175                                self.rest[range + start - 1] =
176                                    self.rest[range + start - 1].wrapping_add(1);
177                            }
178                        }
179                        self
180                    }
181                }
182
183                #[derive(Clone, Copy)]
184                struct Mul<const M: usize> {
185                    last: $Digit,
186                    rest: [$Digit; M],
187                }
188                impl<const M: usize> Mul<M> {
189                    const fn new(uint: $BUint<M>, rhs: $Digit) -> Self {
190                        let mut rest = [0; M];
191                        let mut carry: $Digit = 0;
192                        let mut i = 0;
193                        while i < M {
194                            let (prod, c) =
195                                digit::$Digit::carrying_mul(uint.digits[i], rhs, carry, 0);
196                            carry = c;
197                            rest[i] = prod;
198                            i += 1;
199                        }
200                        Self { last: carry, rest }
201                    }
202                    const fn digit(&self, index: usize) -> $Digit {
203                        if index == M {
204                            self.last
205                        } else {
206                            self.rest[index]
207                        }
208                    }
209                }
210
211                let v_n_m1 = v.digits[n - 1];
212                let v_n_m2 = v.digits[n - 2];
213
214                let mut u = Remainder::new(self, shift);
215
216                let mut j = m + 1; // D2
217                while j > 0 {
218                    j -= 1; // D7
219
220                    let u_jn = u.digit(j + n);
221
222                    #[inline]
223                    const fn tuple_gt(a: ($Digit, $Digit), b: ($Digit, $Digit)) -> bool {
224                        a.1 > b.1 || a.1 == b.1 && a.0 > b.0
225                    }
226
227                    // q_hat will be either `q` or `q + 1`
228                    let mut q_hat = if u_jn < v_n_m1 {
229                        let (mut q_hat, r_hat) =
230                            digit::$Digit::div_rem_wide(u.digit(j + n - 1), u_jn, v_n_m1); // D3
231
232                        if tuple_gt(
233                            digit::$Digit::widening_mul(q_hat, v_n_m2),
234                            (u.digit(j + n - 2), r_hat as $Digit),
235                        ) {
236                            q_hat -= 1;
237
238                            if let Some(r_hat) = r_hat.checked_add(v_n_m1) {
239                                // this checks if `r_hat <= b`, where `b` is the digit base
240                                if tuple_gt(
241                                    digit::$Digit::widening_mul(q_hat, v_n_m2),
242                                    (u.digit(j + n - 2), r_hat as $Digit),
243                                ) {
244                                    q_hat -= 1;
245                                }
246                            }
247                        }
248                        q_hat
249                    } else {
250                        // `u[j + n - 1] >= v[n - 1]` so we know that estimate for q_hat would be larger than `Digit::MAX`. This is either equal to `q` or `q + 1` (very unlikely to be `q + 1`).
251                        $Digit::MAX
252                    };
253                    let (u_new, overflow) = u.sub(Mul::new(v, q_hat), j, n); // D4
254                    u = u_new;
255
256                    if overflow {
257                        // D5 - unlikely, probability of this being true is ~ 2 / b where b is the digit base (i.e. `Digit::MAX + 1`)
258                        q_hat -= 1;
259                        u = u.add(v, j, n);
260                    }
261                    q.digits[j] = q_hat;
262                }
263                (q, u.shr(shift))
264            }
265
266            #[inline]
267            pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) {
268                use core::cmp::Ordering;
269
270                if self.is_zero() {
271                    return (Self::ZERO, Self::ZERO);
272                }
273
274                match self.cmp(&rhs) {
275                    Ordering::Less => (Self::ZERO, self),
276                    Ordering::Equal => (Self::ONE, Self::ZERO),
277                    Ordering::Greater => {
278                        let ldi = rhs.last_digit_index();
279                        if ldi == 0 {
280                            let (div, rem) = self.div_rem_digit(rhs.digits[0]);
281                            (div, Self::from_digit(rem))
282                        } else {
283                            self.basecase_div_rem(rhs, ldi + 1)
284                        }
285                    }
286                }
287            }
288
289            #[inline]
290            pub(crate) const fn div_rem(self, rhs: Self) -> (Self, Self) {
291                if rhs.is_zero() {
292                    div_zero!()
293                } else {
294                    self.div_rem_unchecked(rhs)
295                }
296            }
297
298            #[doc = doc::checked::checked_div!(U)]
299            #[must_use = doc::must_use_op!()]
300            #[inline]
301            pub const fn checked_div(self, rhs: Self) -> Option<Self> {
302                if rhs.is_zero() {
303                    None
304                } else {
305                    Some(self.div_rem_unchecked(rhs).0)
306                }
307            }
308
309            #[doc = doc::checked::checked_div_euclid!(U)]
310            #[must_use = doc::must_use_op!()]
311            #[inline]
312            pub const fn checked_div_euclid(self, rhs: Self) -> Option<Self> {
313                self.checked_div(rhs)
314            }
315
316            #[doc = doc::checked::checked_rem!(U)]
317            #[must_use = doc::must_use_op!()]
318            #[inline]
319            pub const fn checked_rem(self, rhs: Self) -> Option<Self> {
320                if rhs.is_zero() {
321                    None
322                } else {
323                    Some(self.div_rem_unchecked(rhs).1)
324                }
325            }
326
327            #[doc = doc::checked::checked_rem_euclid!(U)]
328            #[must_use = doc::must_use_op!()]
329            #[inline]
330            pub const fn checked_rem_euclid(self, rhs: Self) -> Option<Self> {
331                self.checked_rem(rhs)
332            }
333
334            #[doc = doc::checked::checked_neg!(U)]
335            #[must_use = doc::must_use_op!()]
336            #[inline]
337            pub const fn checked_neg(self) -> Option<Self> {
338                if self.is_zero() {
339                    Some(self)
340                } else {
341                    None
342                }
343            }
344
345            #[doc = doc::checked::checked_shl!(U)]
346            #[must_use = doc::must_use_op!()]
347            #[inline]
348            pub const fn checked_shl(self, rhs: ExpType) -> Option<Self> {
349                if rhs >= Self::BITS {
350                    None
351                } else {
352                    unsafe { Some(Self::unchecked_shl_internal(self, rhs)) }
353                }
354            }
355
356            #[doc = doc::checked::checked_shr!(U)]
357            #[must_use = doc::must_use_op!()]
358            #[inline]
359            pub const fn checked_shr(self, rhs: ExpType) -> Option<Self> {
360                if rhs >= Self::BITS {
361                    None
362                } else {
363                    unsafe { Some(Self::unchecked_shr_internal(self, rhs)) }
364                }
365            }
366
367            #[doc = doc::checked::checked_pow!(U)]
368            #[must_use = doc::must_use_op!()]
369            #[inline]
370            pub const fn checked_pow(mut self, mut pow: ExpType) -> Option<Self> {
371                // https://en.wikipedia.org/wiki/Exponentiation_by_squaring#Basic_method
372                if pow == 0 {
373                    return Some(Self::ONE);
374                }
375                let mut y = Self::ONE;
376                while pow > 1 {
377                    if pow & 1 == 1 {
378                        y = match self.checked_mul(y) {
379                            Some(m) => m,
380                            None => return None,
381                        };
382                    }
383                    self = match self.checked_mul(self) {
384                        Some(m) => m,
385                        None => return None,
386                    };
387                    pow >>= 1;
388                }
389                self.checked_mul(y)
390            }
391
392            #[doc = doc::checked::checked_next_multiple_of!(U)]
393            #[must_use = doc::must_use_op!()]
394            #[inline]
395            pub const fn checked_next_multiple_of(self, rhs: Self) -> Option<Self> {
396                match self.checked_rem(rhs) {
397                    Some(rem) => {
398                        if rem.is_zero() {
399                            // `rhs` divides `self` exactly so just return `self`
400                            Some(self)
401                        } else {
402                            // `next_multiple = floor(self / rhs) * rhs + rhs = (self - rem) + rhs`
403                            self.checked_add(rhs.sub(rem))
404                        }
405                    }
406                    None => None,
407                }
408            }
409
410            #[doc = doc::checked::checked_ilog2!(U)]
411            #[must_use = doc::must_use_op!()]
412            #[inline]
413            pub const fn checked_ilog2(self) -> Option<ExpType> {
414                self.bits().checked_sub(1)
415            }
416
417            #[inline]
418            const fn iilog(m: ExpType, b: Self, k: Self) -> (ExpType, Self) {
419                // https://people.csail.mit.edu/jaffer/III/iilog.pdf
420                if b.gt(&k) {
421                    (m, k)
422                } else {
423                    let (new, q) = Self::iilog(m << 1, b.mul(b), k.div_rem_unchecked(b).0);
424                    if b.gt(&q) {
425                        (new, q)
426                    } else {
427                        (new + m, q.div(b))
428                    }
429                }
430            }
431
432            #[doc = doc::checked::checked_ilog10!(U)]
433            #[must_use = doc::must_use_op!()]
434            #[inline]
435            pub const fn checked_ilog10(self) -> Option<ExpType> {
436                if self.is_zero() {
437                    return None;
438                }
439                if Self::TEN.gt(&self) {
440                    return Some(0);
441                }
442                Some(Self::iilog(1, Self::TEN, self.div_rem_digit(10).0).0)
443            }
444
445            #[doc = doc::checked::checked_ilog!(U)]
446            #[must_use = doc::must_use_op!()]
447            #[inline]
448            pub const fn checked_ilog(self, base: Self) -> Option<ExpType> {
449                use core::cmp::Ordering;
450                match base.cmp(&Self::TWO) {
451                    Ordering::Less => None,
452                    Ordering::Equal => self.checked_ilog2(),
453                    Ordering::Greater => {
454                        if self.is_zero() {
455                            return None;
456                        }
457                        if base.gt(&self) {
458                            return Some(0);
459                        }
460                        Some(Self::iilog(1, base, self.div(base)).0)
461                    }
462                }
463            }
464
465            #[doc = doc::checked::checked_next_power_of_two!(U 256)]
466            #[must_use = doc::must_use_op!()]
467            #[inline]
468            pub const fn checked_next_power_of_two(self) -> Option<Self> {
469                if self.is_power_of_two() {
470                    return Some(self);
471                }
472                let bits = self.bits();
473                if bits == Self::BITS {
474                    return None;
475                }
476                Some(Self::power_of_two(bits))
477            }
478        }
479    };
480}
481
482crate::macro_impl!(checked);