reweb3_num/buint/
overflowing.rs

1use crate::digit;
2use crate::doc;
3use crate::ExpType;
4
5macro_rules! overflowing {
6    ($BUint: ident, $BInt: ident, $Digit: ident) => {
7        #[doc = doc::overflowing::impl_desc!()]
8        impl<const N: usize> $BUint<N> {
9            #[doc = doc::overflowing::overflowing_add!(U)]
10            #[must_use = doc::must_use_op!()]
11            #[inline]
12            pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
13                let mut out = Self::ZERO;
14                let mut carry = false;
15                let mut i = 0;
16                while i < N {
17                    let result = digit::$Digit::carrying_add(self.digits[i], rhs.digits[i], carry);
18                    out.digits[i] = result.0;
19                    carry = result.1;
20                    i += 1;
21                }
22                (out, carry)
23            }
24
25            #[doc = doc::overflowing::overflowing_add_signed!(U)]
26            #[must_use = doc::must_use_op!()]
27            #[inline]
28            pub const fn overflowing_add_signed(self, rhs: $BInt<N>) -> (Self, bool) {
29                let (sum, overflow) = self.overflowing_add(rhs.to_bits());
30                (sum, rhs.is_negative() != overflow)
31            }
32
33            #[doc = doc::overflowing::overflowing_sub!(U)]
34            #[must_use = doc::must_use_op!()]
35            #[inline]
36            pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
37                let mut out = Self::ZERO;
38                let mut borrow = false;
39                let mut i = 0;
40                while i < N {
41                    let result =
42                        digit::$Digit::borrowing_sub(self.digits[i], rhs.digits[i], borrow);
43                    out.digits[i] = result.0;
44                    borrow = result.1;
45                    i += 1;
46                }
47                (out, borrow)
48            }
49
50            #[inline]
51            const fn long_mul(self, rhs: Self) -> (Self, bool) {
52                let mut overflow = false;
53                let mut out = Self::ZERO;
54                let mut carry: $Digit;
55
56                let mut i = 0;
57                while i < N {
58                    carry = 0;
59                    let mut j = 0;
60                    while j < N {
61                        let index = i + j;
62                        if index < N {
63                            let (prod, c) = digit::$Digit::carrying_mul(
64                                self.digits[i],
65                                rhs.digits[j],
66                                carry,
67                                out.digits[index],
68                            );
69                            out.digits[index] = prod;
70                            carry = c;
71                        } else if self.digits[i] != 0 && rhs.digits[j] != 0 {
72                            overflow = true;
73                            break;
74                        }
75                        j += 1;
76                    }
77                    if carry != 0 {
78                        overflow = true;
79                    }
80                    i += 1;
81                }
82                (out, overflow)
83            }
84
85            #[doc = doc::overflowing::overflowing_mul!(U)]
86            #[must_use = doc::must_use_op!()]
87            #[inline]
88            pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
89                // TODO: implement a faster multiplication algorithm for large values of `N`
90                self.long_mul(rhs)
91            }
92
93            #[doc = doc::overflowing::overflowing_div!(U)]
94            #[must_use = doc::must_use_op!()]
95            #[inline]
96            pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
97                (self.wrapping_div(rhs), false)
98            }
99
100            #[doc = doc::overflowing::overflowing_div_euclid!(U)]
101            #[must_use = doc::must_use_op!()]
102            #[inline]
103            pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
104                self.overflowing_div(rhs)
105            }
106
107            #[doc = doc::overflowing::overflowing_rem!(U)]
108            #[must_use = doc::must_use_op!()]
109            #[inline]
110            pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
111                (self.wrapping_rem(rhs), false)
112            }
113
114            #[doc = doc::overflowing::overflowing_rem_euclid!(U)]
115            #[must_use = doc::must_use_op!()]
116            #[inline]
117            pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
118                self.overflowing_rem(rhs)
119            }
120
121            #[doc = doc::overflowing::overflowing_neg!(U)]
122            #[must_use = doc::must_use_op!()]
123            #[inline]
124            pub const fn overflowing_neg(self) -> (Self, bool) {
125                let (a, b) = (self.not()).overflowing_add(Self::ONE);
126                (a, !b)
127            }
128
129            #[doc = doc::overflowing::overflowing_shl!(U)]
130            #[must_use = doc::must_use_op!()]
131            #[inline]
132            pub const fn overflowing_shl(self, rhs: ExpType) -> (Self, bool) {
133                unsafe {
134                    if rhs >= Self::BITS {
135                        (
136                            Self::unchecked_shl_internal(self, rhs & (Self::BITS - 1)),
137                            true,
138                        )
139                    } else {
140                        (Self::unchecked_shl_internal(self, rhs), false)
141                    }
142                }
143            }
144
145            #[doc = doc::overflowing::overflowing_shr!(U)]
146            #[must_use = doc::must_use_op!()]
147            #[inline]
148            pub const fn overflowing_shr(self, rhs: ExpType) -> (Self, bool) {
149                unsafe {
150                    if rhs >= Self::BITS {
151                        (
152                            Self::unchecked_shr_internal(self, rhs & (Self::BITS - 1)),
153                            true,
154                        )
155                    } else {
156                        (Self::unchecked_shr_internal(self, rhs), false)
157                    }
158                }
159            }
160
161            #[doc = doc::overflowing::overflowing_pow!(U)]
162            #[must_use = doc::must_use_op!()]
163            #[inline]
164            pub const fn overflowing_pow(mut self, mut pow: ExpType) -> (Self, bool) {
165                if pow == 0 {
166                    return (Self::ONE, false);
167                }
168                let mut overflow = false;
169                let mut y = Self::ONE;
170                while pow > 1 {
171                    if pow & 1 == 1 {
172                        let (prod, o) = y.overflowing_mul(self);
173                        overflow |= o;
174                        y = prod;
175                    }
176                    let (prod, o) = self.overflowing_mul(self);
177                    overflow |= o;
178                    self = prod;
179                    pow >>= 1;
180                }
181                let (prod, o) = self.overflowing_mul(y);
182                (prod, o || overflow)
183            }
184        }
185    };
186}
187
188crate::macro_impl!(overflowing);