malachite_nz/integer/arithmetic/
shr.rs

1// Copyright © 2025 Mikhail Hogrefe
2//
3// This file is part of Malachite.
4//
5// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
6// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
7// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
8
9use crate::integer::Integer;
10use crate::natural::Natural;
11use core::ops::{Shl, ShlAssign, Shr, ShrAssign};
12use malachite_base::num::arithmetic::traits::{ShrRound, ShrRoundAssign, UnsignedAbs};
13use malachite_base::num::basic::traits::Zero;
14use malachite_base::rounding_modes::RoundingMode::*;
15
16fn shr_unsigned_ref<'a, T>(x: &'a Integer, bits: T) -> Integer
17where
18    &'a Natural: Shr<T, Output = Natural> + ShrRound<T, Output = Natural>,
19{
20    match *x {
21        Integer {
22            sign: true,
23            ref abs,
24        } => Integer {
25            sign: true,
26            abs: abs >> bits,
27        },
28        Integer {
29            sign: false,
30            ref abs,
31        } => {
32            let abs_shifted = abs.shr_round(bits, Ceiling).0;
33            if abs_shifted == 0 {
34                Integer::ZERO
35            } else {
36                Integer {
37                    sign: false,
38                    abs: abs_shifted,
39                }
40            }
41        }
42    }
43}
44
45fn shr_assign_unsigned<T>(x: &mut Integer, bits: T)
46where
47    Natural: ShrAssign<T> + ShrRoundAssign<T>,
48{
49    match *x {
50        Integer {
51            sign: true,
52            ref mut abs,
53        } => {
54            *abs >>= bits;
55        }
56        Integer {
57            sign: false,
58            ref mut abs,
59        } => {
60            abs.shr_round_assign(bits, Ceiling);
61            if *abs == 0 {
62                x.sign = true;
63            }
64        }
65    }
66}
67
68macro_rules! impl_shr_unsigned {
69    ($t:ident) => {
70        impl Shr<$t> for Integer {
71            type Output = Integer;
72
73            /// Right-shifts an [`Integer`] (divides it by a power of 2 and takes the floor), taking
74            /// it by value.
75            ///
76            /// $$
77            /// f(x, k) = \left \lfloor \frac{x}{2^k} \right \rfloor.
78            /// $$
79            ///
80            /// # Worst-case complexity
81            /// $T(n) = O(n)$
82            ///
83            /// $M(n) = O(1)$
84            ///
85            /// where $T$ is time, $M$ is additional memory and $n$ is `max(1,
86            /// self.significant_bits() - bits)`.
87            ///
88            /// # Examples
89            /// See [here](super::shr#shr).
90            #[inline]
91            fn shr(mut self, bits: $t) -> Integer {
92                self >>= bits;
93                self
94            }
95        }
96
97        impl<'a> Shr<$t> for &Integer {
98            type Output = Integer;
99
100            /// Right-shifts an [`Integer`] (divides it by a power of 2 and takes the floor), taking
101            /// it by reference.
102            ///
103            /// $$
104            /// f(x, k) = \left \lfloor \frac{x}{2^k} \right \rfloor.
105            /// $$
106            ///
107            /// # Worst-case complexity
108            /// $T(n) = O(n)$
109            ///
110            /// $M(n) = O(1)$
111            ///
112            /// where $T$ is time, $M$ is additional memory and $n$ is `max(1,
113            /// self.significant_bits() - bits)`.
114            ///
115            /// # Examples
116            /// See [here](super::shr#shr).
117            #[inline]
118            fn shr(self, bits: $t) -> Integer {
119                shr_unsigned_ref(self, bits)
120            }
121        }
122
123        impl ShrAssign<$t> for Integer {
124            /// Right-shifts an [`Integer`] (divides it by a power of 2 and takes the floor), in
125            /// place.
126            ///
127            /// $$
128            /// x \gets \left \lfloor \frac{x}{2^k} \right \rfloor.
129            /// $$
130            ///
131            /// # Worst-case complexity
132            /// $T(n) = O(n)$
133            ///
134            /// $M(n) = O(1)$
135            ///
136            /// where $T$ is time, $M$ is additional memory and $n$ is `max(1,
137            /// self.significant_bits() - bits)`.
138            ///
139            /// # Examples
140            /// See [here](super::shr#shr_assign).
141            #[inline]
142            fn shr_assign(&mut self, bits: $t) {
143                shr_assign_unsigned(self, bits);
144            }
145        }
146    };
147}
148apply_to_unsigneds!(impl_shr_unsigned);
149
150fn shr_signed_ref<'a, U, S: Copy + Ord + UnsignedAbs<Output = U> + Zero>(
151    x: &'a Integer,
152    bits: S,
153) -> Integer
154where
155    &'a Integer: Shl<U, Output = Integer> + Shr<U, Output = Integer>,
156{
157    if bits >= S::ZERO {
158        x >> bits.unsigned_abs()
159    } else {
160        x << bits.unsigned_abs()
161    }
162}
163
164fn shr_assign_signed<U, S: Copy + Ord + UnsignedAbs<Output = U> + Zero>(x: &mut Integer, bits: S)
165where
166    Integer: ShlAssign<U> + ShrAssign<U>,
167{
168    if bits >= S::ZERO {
169        *x >>= bits.unsigned_abs();
170    } else {
171        *x <<= bits.unsigned_abs();
172    }
173}
174
175macro_rules! impl_shr_signed {
176    ($t:ident) => {
177        impl Shr<$t> for Integer {
178            type Output = Integer;
179
180            /// Right-shifts an [`Integer`] (divides it by a power of 2 and takes the floor or
181            /// multiplies it by a power of 2), taking it by value.
182            ///
183            /// $$
184            /// f(x, k) = \left \lfloor \frac{x}{2^k} \right \rfloor.
185            /// $$
186            ///
187            /// # Worst-case complexity
188            /// $T(n) = O(n)$
189            ///
190            /// $M(n) = O(1)$
191            ///
192            /// where $T$ is time, $M$ is additional memory and $n$ is `max(1,
193            /// self.significant_bits() - bits)`.
194            ///
195            /// # Examples
196            /// See [here](super::shr#shr).
197            #[inline]
198            fn shr(mut self, bits: $t) -> Integer {
199                self >>= bits;
200                self
201            }
202        }
203
204        impl<'a> Shr<$t> for &Integer {
205            type Output = Integer;
206
207            /// Right-shifts an [`Integer`] (divides it by a power of 2 and takes the floor or
208            /// multiplies it by a power of 2), taking it by reference.
209            ///
210            /// $$
211            /// f(x, k) = \left \lfloor \frac{x}{2^k} \right \rfloor.
212            /// $$
213            ///
214            /// # Worst-case complexity
215            /// $T(n) = O(n)$
216            ///
217            /// $M(n) = O(1)$
218            ///
219            /// where $T$ is time, $M$ is additional memory and $n$ is `max(1,
220            /// self.significant_bits() - bits)`.
221            ///
222            /// # Examples
223            /// See [here](super::shr#shr).
224            #[inline]
225            fn shr(self, bits: $t) -> Integer {
226                shr_signed_ref(self, bits)
227            }
228        }
229
230        impl ShrAssign<$t> for Integer {
231            /// Right-shifts an [`Integer`] (divides it by a power of 2 and takes the floor or
232            /// multiplies it by a power of 2), in place.
233            ///
234            /// $$
235            /// x \gets \left \lfloor \frac{x}{2^k} \right \rfloor.
236            /// $$
237            ///
238            /// # Worst-case complexity
239            /// $T(n) = O(n)$
240            ///
241            /// $M(n) = O(1)$
242            ///
243            /// where $T$ is time, $M$ is additional memory and $n$ is `max(1,
244            /// self.significant_bits() - bits)`.
245            ///
246            /// # Examples
247            /// See [here](super::shr#shr_assign).
248            #[inline]
249            fn shr_assign(&mut self, bits: $t) {
250                shr_assign_signed(self, bits)
251            }
252        }
253    };
254}
255apply_to_signeds!(impl_shr_signed);