Skip to main content

bnum/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            #[doc = doc::overflowing::overflowing_mul!(U)]
51            #[must_use = doc::must_use_op!()]
52            #[inline]
53            pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
54                // TODO: implement a faster multiplication algorithm for large values of `N`
55                self.long_mul(rhs)
56            }
57
58            #[doc = doc::overflowing::overflowing_div!(U)]
59            #[must_use = doc::must_use_op!()]
60            #[inline]
61            pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) {
62                (self.wrapping_div(rhs), false)
63            }
64
65            #[doc = doc::overflowing::overflowing_div_euclid!(U)]
66            #[must_use = doc::must_use_op!()]
67            #[inline]
68            pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) {
69                self.overflowing_div(rhs)
70            }
71
72            #[doc = doc::overflowing::overflowing_rem!(U)]
73            #[must_use = doc::must_use_op!()]
74            #[inline]
75            pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) {
76                (self.wrapping_rem(rhs), false)
77            }
78
79            #[doc = doc::overflowing::overflowing_rem_euclid!(U)]
80            #[must_use = doc::must_use_op!()]
81            #[inline]
82            pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) {
83                self.overflowing_rem(rhs)
84            }
85
86            #[doc = doc::overflowing::overflowing_neg!(U)]
87            #[must_use = doc::must_use_op!()]
88            #[inline]
89            pub const fn overflowing_neg(self) -> (Self, bool) {
90                let (a, b) = (self.not()).overflowing_add(Self::ONE);
91                (a, !b)
92            }
93
94            #[doc = doc::overflowing::overflowing_shl!(U)]
95            #[must_use = doc::must_use_op!()]
96            #[inline]
97            pub const fn overflowing_shl(self, rhs: ExpType) -> (Self, bool) {
98                unsafe {
99                    if rhs >= Self::BITS {
100                        (
101                            Self::unchecked_shl_internal(self, rhs & (Self::BITS - 1)),
102                            true,
103                        )
104                    } else {
105                        (Self::unchecked_shl_internal(self, rhs), false)
106                    }
107                }
108            }
109
110            #[doc = doc::overflowing::overflowing_shr!(U)]
111            #[must_use = doc::must_use_op!()]
112            #[inline]
113            pub const fn overflowing_shr(self, rhs: ExpType) -> (Self, bool) {
114                unsafe {
115                    if rhs >= Self::BITS {
116                        (
117                            Self::unchecked_shr_internal(self, rhs & (Self::BITS - 1)),
118                            true,
119                        )
120                    } else {
121                        (Self::unchecked_shr_internal(self, rhs), false)
122                    }
123                }
124            }
125
126            #[doc = doc::overflowing::overflowing_pow!(U)]
127            #[must_use = doc::must_use_op!()]
128            #[inline]
129            pub const fn overflowing_pow(mut self, mut pow: ExpType) -> (Self, bool) {
130                // exponentiation by squaring
131                if pow == 0 {
132                    return (Self::ONE, false);
133                }
134                let mut overflow = false;
135                let mut y = Self::ONE;
136                while pow > 1 {
137                    if pow & 1 == 1 {
138                        let (prod, o) = y.overflowing_mul(self);
139                        overflow |= o;
140                        y = prod;
141                    }
142                    let (prod, o) = self.overflowing_mul(self);
143                    overflow |= o;
144                    self = prod;
145                    pow >>= 1;
146                }
147                let (prod, o) = self.overflowing_mul(y);
148                (prod, o || overflow)
149            }
150        }
151    };
152}
153
154#[cfg(test)]
155crate::test::all_digit_tests! {
156    use crate::test::{test_bignum, types::utest};
157
158    test_bignum! {
159        function: <utest>::overflowing_add(a: utest, b: utest)
160    }
161    test_bignum! {
162        function: <utest>::overflowing_sub(a: utest, b: utest)
163    }
164    test_bignum! {
165        function: <utest>::overflowing_mul(a: utest, b: utest)
166    }
167    test_bignum! {
168        function: <utest>::overflowing_div(a: utest, b: utest),
169        skip: b == 0
170    }
171    test_bignum! {
172        function: <utest>::overflowing_div_euclid(a: utest, b: utest),
173        skip: b == 0
174    }
175    test_bignum! {
176        function: <utest>::overflowing_rem(a: utest, b: utest),
177        skip: b == 0
178    }
179    test_bignum! {
180        function: <utest>::overflowing_rem_euclid(a: utest, b: utest),
181        skip: b == 0
182    }
183    test_bignum! {
184        function: <utest>::overflowing_neg(a: utest)
185    }
186    test_bignum! {
187        function: <utest>::overflowing_shl(a: utest, b: u16)
188    }
189    test_bignum! {
190        function: <utest>::overflowing_shr(a: utest, b: u16)
191    }
192    test_bignum! {
193        function: <utest>::overflowing_pow(a: utest, b: u16)
194    }
195}
196
197crate::macro_impl!(overflowing);