reweb3_num/bint/
overflowing.rs

1use crate::digit;
2use crate::errors::div_zero;
3use crate::{doc, ExpType};
4
5macro_rules! overflowing {
6    ($BUint: ident, $BInt: ident, $Digit: ident) => {
7        #[doc = doc::overflowing::impl_desc!()]
8        impl<const N: usize> $BInt<N> {
9            #[doc = doc::overflowing::overflowing_add!(I)]
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
16                let self_digits = self.bits.digits;
17                let rhs_digits = rhs.bits.digits;
18
19                let mut i = 0;
20                while i < Self::N_MINUS_1 {
21                    let (sum, c) =
22                        digit::$Digit::carrying_add(self_digits[i], rhs_digits[i], carry);
23                    out.bits.digits[i] = sum;
24                    carry = c;
25                    i += 1;
26                }
27                let (sum, carry) = digit::$Digit::carrying_add_signed(
28                    self_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit,
29                    rhs_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit,
30                    carry,
31                );
32                out.bits.digits[Self::N_MINUS_1] = sum as $Digit;
33
34                (out, carry)
35            }
36
37            #[doc = doc::overflowing::overflowing_add_unsigned!(I)]
38            #[must_use = doc::must_use_op!()]
39            #[inline]
40            pub const fn overflowing_add_unsigned(self, rhs: $BUint<N>) -> (Self, bool) {
41                let rhs = Self::from_bits(rhs);
42                let (sum, overflow) = self.overflowing_add(rhs);
43                (sum, rhs.is_negative() != overflow)
44            }
45
46            #[doc = doc::overflowing::overflowing_sub!(I)]
47            #[must_use = doc::must_use_op!()]
48            #[inline]
49            pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
50                let mut out = Self::ZERO;
51                let mut borrow = false;
52
53                let self_digits = self.bits.digits;
54                let rhs_digits = rhs.bits.digits;
55
56                let mut i = 0;
57                while i < Self::N_MINUS_1 {
58                    let (sub, b) =
59                        digit::$Digit::borrowing_sub(self_digits[i], rhs_digits[i], borrow);
60                    out.bits.digits[i] = sub;
61                    borrow = b;
62                    i += 1;
63                }
64                let (sub, borrow) = digit::$Digit::borrowing_sub_signed(
65                    self_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit,
66                    rhs_digits[Self::N_MINUS_1] as digit::$Digit::SignedDigit,
67                    borrow,
68                );
69                out.bits.digits[Self::N_MINUS_1] = sub as $Digit;
70
71                (out, borrow)
72            }
73
74            #[doc = doc::overflowing::overflowing_sub_unsigned!(I)]
75            #[must_use = doc::must_use_op!()]
76            #[inline]
77            pub const fn overflowing_sub_unsigned(self, rhs: $BUint<N>) -> (Self, bool) {
78                let rhs = Self::from_bits(rhs);
79                let (sum, overflow) = self.overflowing_sub(rhs);
80                (sum, rhs.is_negative() != overflow)
81            }
82
83            const BITS_MINUS_1: ExpType = (Self::BITS - 1) as ExpType;
84
85            #[doc = doc::overflowing::overflowing_mul!(I)]
86            #[must_use = doc::must_use_op!()]
87            #[inline]
88            pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
89                let (uint, overflow) = self.unsigned_abs().overflowing_mul(rhs.unsigned_abs());
90                let out = Self::from_bits(uint);
91                if self.is_negative() == rhs.is_negative() {
92                    (out, overflow || out.is_negative())
93                } else {
94                    match out.checked_neg() {
95                        Some(n) => (n, overflow || out.is_negative()),
96                        None => (out, overflow),
97                    }
98                }
99            }
100
101            #[inline]
102            pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) {
103                if self.eq(&Self::MIN) && rhs.is_one() {
104                    return (self, Self::ZERO);
105                }
106                let (div, rem) = self.unsigned_abs().div_rem_unchecked(rhs.unsigned_abs());
107                let (div, rem) = (Self::from_bits(div), Self::from_bits(rem));
108
109                match (self.is_negative(), rhs.is_negative()) {
110                    (false, false) => (div, rem),
111                    (false, true) => (div.neg(), rem),
112                    (true, false) => (div.neg(), rem.neg()),
113                    (true, true) => (div, rem.neg()),
114                }
115            }
116
117            #[doc = doc::overflowing::overflowing_div!(I)]
118            #[must_use = doc::must_use_op!()]
119            #[inline]
120            pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
121                if rhs.is_zero() {
122                    div_zero!()
123                }
124                if self.eq(&Self::MIN) {
125                    if rhs.eq(&Self::NEG_ONE) {
126                        return (self, true);
127                    } else if rhs.is_one() {
128                        return (self, false);
129                    }
130                }
131                (self.div_rem_unchecked(rhs).0, false)
132            }
133
134            #[doc = doc::overflowing::overflowing_div_euclid!(I)]
135            #[must_use = doc::must_use_op!()]
136            #[inline]
137            pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
138                if rhs.is_zero() {
139                    div_zero!()
140                }
141                if self.eq(&Self::MIN) {
142                    if rhs.eq(&Self::NEG_ONE) {
143                        return (self, true);
144                    } else if rhs.is_one() {
145                        return (self, false);
146                    }
147                }
148                let (div, rem) = self.div_rem_unchecked(rhs);
149                if self.is_negative() {
150                    let r_neg = rhs.is_negative();
151                    if !rem.is_zero() {
152                        if r_neg {
153                            return (div.add(Self::ONE), false);
154                        } else {
155                            return (div.sub(Self::ONE), false);
156                        };
157                    }
158                }
159                (div, false)
160            }
161
162            #[doc = doc::overflowing::overflowing_rem!(I)]
163            #[must_use = doc::must_use_op!()]
164            #[inline]
165            pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
166                if rhs.is_zero() {
167                    div_zero!()
168                }
169                if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) {
170                    (Self::ZERO, true)
171                } else {
172                    (self.div_rem_unchecked(rhs).1, false)
173                }
174            }
175
176            #[doc = doc::overflowing::overflowing_rem_euclid!(I)]
177            #[must_use = doc::must_use_op!()]
178            #[inline]
179            pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
180                if rhs.is_zero() {
181                    div_zero!()
182                }
183                if self.eq(&Self::MIN) && rhs.eq(&Self::NEG_ONE) {
184                    (Self::ZERO, true)
185                } else {
186                    let mut rem = self.div_rem_unchecked(rhs).1;
187                    if rem.is_negative() {
188                        if rhs.is_negative() {
189                            rem = rem.wrapping_sub(rhs);
190                        } else {
191                            rem = rem.wrapping_add(rhs);
192                        }
193                    }
194                    (rem, false)
195                }
196            }
197
198            #[doc = doc::overflowing::overflowing_neg!(I)]
199            #[must_use = doc::must_use_op!()]
200            #[inline]
201            pub const fn overflowing_neg(mut self) -> (Self, bool) {
202                let mut i = 0;
203                while i < N - 1 {
204                    let (s, o) = (!self.bits.digits[i]).overflowing_add(1); // TODO: use overflowing add on signed integer digit instead
205                    self.bits.digits[i] = s;
206                    if !o {
207                        i += 1;
208                        while i < N {
209                            self.bits.digits[i] = !self.bits.digits[i];
210                            i += 1;
211                        }
212                        return (self, false);
213                    }
214                    i += 1;
215                }
216                let (s, o) =
217                    (!self.bits.digits[i] as digit::$Digit::SignedDigit).overflowing_add(1);
218                self.bits.digits[i] = s as $Digit;
219                (self, o)
220            }
221
222            #[doc = doc::overflowing::overflowing_shl!(I)]
223            #[must_use = doc::must_use_op!()]
224            #[inline]
225            pub const fn overflowing_shl(self, rhs: ExpType) -> (Self, bool) {
226                let (uint, overflow) = self.bits.overflowing_shl(rhs);
227                (Self::from_bits(uint), overflow)
228            }
229
230            #[doc = doc::overflowing::overflowing_shr!(I)]
231            #[must_use = doc::must_use_op!()]
232            #[inline]
233            pub const fn overflowing_shr(self, rhs: ExpType) -> (Self, bool) {
234                let bits = self.to_bits();
235                let (overflow, shift) = if rhs >= Self::BITS {
236                    (true, rhs & Self::BITS_MINUS_1)
237                } else {
238                    (false, rhs)
239                };
240                let u = unsafe {
241                    if self.is_negative() {
242                        $BUint::unchecked_shr_pad_internal::<true>(bits, shift)
243                    } else {
244                        $BUint::unchecked_shr_pad_internal::<false>(bits, shift)
245                    }
246                };
247                (Self::from_bits(u), overflow)
248            }
249
250            #[doc = doc::overflowing::overflowing_abs!(I)]
251            #[must_use = doc::must_use_op!()]
252            #[inline]
253            pub const fn overflowing_abs(self) -> (Self, bool) {
254                if self.is_negative() {
255                    self.overflowing_neg()
256                } else {
257                    (self, false)
258                }
259            }
260
261            #[doc = doc::overflowing::overflowing_pow!(I)]
262            #[must_use = doc::must_use_op!()]
263            #[inline]
264            pub const fn overflowing_pow(self, pow: ExpType) -> (Self, bool) {
265                let (u, mut overflow) = self.unsigned_abs().overflowing_pow(pow);
266                let out_neg = self.is_negative() && pow & 1 == 1;
267                let mut out = Self::from_bits(u);
268                if out_neg {
269                    out = out.wrapping_neg();
270                    overflow = overflow || !out.is_negative();
271                } else {
272                    overflow = overflow || out.is_negative();
273                }
274                (out, overflow)
275            }
276        }
277    };
278}
279
280crate::macro_impl!(overflowing);