Skip to main content

malachite_nz/integer_vector/arithmetic/
entrywise_shr_round.rs

1// Copyright © 2026 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::integer_vector::IntegerVector;
11use malachite_base::num::arithmetic::traits::{
12    EntrywiseShrRound, EntrywiseShrRoundAssign, ShrRound, ShrRoundAssign,
13};
14use malachite_base::rounding_modes::RoundingMode;
15
16// Shifts every element right by `bits`, rounding each according to `rm`.
17fn entrywise_shr_round_ref<T: Copy>(v: &IntegerVector, bits: T, rm: RoundingMode) -> IntegerVector
18where
19    for<'a> &'a Integer: ShrRound<T, Output = Integer>,
20{
21    IntegerVector {
22        elements: v.elements.iter().map(|x| x.shr_round(bits, rm).0).collect(),
23    }
24}
25
26// Shifts every element right by `bits`, rounding each according to `rm`, in place.
27fn entrywise_shr_round_assign<T: Copy>(v: &mut IntegerVector, bits: T, rm: RoundingMode)
28where
29    Integer: ShrRoundAssign<T>,
30{
31    for x in &mut v.elements {
32        x.shr_round_assign(bits, rm);
33    }
34}
35
36macro_rules! impl_integer_vector_entrywise_shr_round_unsigned {
37    ($t:ident) => {
38        impl EntrywiseShrRound<$t> for IntegerVector {
39            type Output = IntegerVector;
40
41            /// Right-shifts an [`IntegerVector`] (divides it by a power of 2), taking it by value,
42            /// and rounds every element according to the specified rounding mode.
43            ///
44            /// Each element is rounded as by
45            /// [`ShrRound`](malachite_base::num::arithmetic::traits::ShrRound), but no
46            /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
47            /// elements may be rounded in different directions. Passing `Floor` is equivalent to
48            /// using `>>`.
49            ///
50            /// $f(v, k, r)_i = \operatorname{round}(v_i/2^k)$, where $\operatorname{round}$ rounds
51            /// according to `rm`.
52            ///
53            /// # Worst-case complexity
54            /// $T(n, k) = O(n + k)$
55            ///
56            /// $M(n, k) = O(n + k)$
57            ///
58            /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the
59            /// elements, and $k$ is `self.dimension()`.
60            ///
61            /// # Panics
62            /// Panics if `rm` is `Exact` and some element is not divisible by $2^k$.
63            ///
64            /// # Examples
65            /// See [here](super::entrywise_shr_round#entrywise_shr_round).            /// With `rm`
66            /// equal to `Down`, this is equivalent to `_fmpz_vec_scalar_tdiv_q_2exp` from
67            /// `fmpz_vec/scalar.c`, FLINT 3.6.0.
68            #[inline]
69            fn entrywise_shr_round(mut self, bits: $t, rm: RoundingMode) -> IntegerVector {
70                self.entrywise_shr_round_assign(bits, rm);
71                self
72            }
73        }
74
75        impl EntrywiseShrRound<$t> for &IntegerVector {
76            type Output = IntegerVector;
77
78            /// Right-shifts an [`IntegerVector`] (divides it by a power of 2), taking it by
79            /// reference, and rounds every element according to the specified rounding mode.
80            ///
81            /// Each element is rounded as by
82            /// [`ShrRound`](malachite_base::num::arithmetic::traits::ShrRound), but no
83            /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
84            /// elements may be rounded in different directions. Passing `Floor` is equivalent to
85            /// using `>>`.
86            ///
87            /// $f(v, k, r)_i = \operatorname{round}(v_i/2^k)$, where $\operatorname{round}$ rounds
88            /// according to `rm`.
89            ///
90            /// # Worst-case complexity
91            /// $T(n, k) = O(n + k)$
92            ///
93            /// $M(n, k) = O(n + k)$
94            ///
95            /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the
96            /// elements, and $k$ is `self.dimension()`.
97            ///
98            /// # Panics
99            /// Panics if `rm` is `Exact` and some element is not divisible by $2^k$.
100            ///
101            /// # Examples
102            /// See [here](super::entrywise_shr_round#entrywise_shr_round).            /// With `rm`
103            /// equal to `Down`, this is equivalent to `_fmpz_vec_scalar_tdiv_q_2exp` from
104            /// `fmpz_vec/scalar.c`, FLINT 3.6.0.
105            #[inline]
106            fn entrywise_shr_round(self, bits: $t, rm: RoundingMode) -> IntegerVector {
107                entrywise_shr_round_ref(self, bits, rm)
108            }
109        }
110
111        impl EntrywiseShrRoundAssign<$t> for IntegerVector {
112            /// Right-shifts an [`IntegerVector`] (divides it by a power of 2), in place, and rounds
113            /// every element according to the specified rounding mode.
114            ///
115            /// Each element is rounded as by
116            /// [`ShrRound`](malachite_base::num::arithmetic::traits::ShrRound), but no
117            /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
118            /// elements may be rounded in different directions. Passing `Floor` is equivalent to
119            /// using `>>`.
120            ///
121            /// $v_i \gets \operatorname{round}(v_i/2^k)$, where $\operatorname{round}$ rounds
122            /// according to `rm`.
123            ///
124            /// # Worst-case complexity
125            /// $T(n, k) = O(n + k)$
126            ///
127            /// $M(k) = O(1)$
128            ///
129            /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the
130            /// elements, and $k$ is `self.dimension()`.
131            ///
132            /// # Panics
133            /// Panics if `rm` is `Exact` and some element is not divisible by $2^k$.
134            ///
135            /// # Examples
136            /// See [here](super::entrywise_shr_round#entrywise_shr_round_assign).            ///
137            /// With `rm` equal to `Down`, this is equivalent to `_fmpz_vec_scalar_tdiv_q_2exp` from
138            /// `fmpz_vec/scalar.c`, FLINT 3.6.0.
139            #[inline]
140            fn entrywise_shr_round_assign(&mut self, bits: $t, rm: RoundingMode) {
141                entrywise_shr_round_assign(self, bits, rm);
142            }
143        }
144    };
145}
146apply_to_unsigneds!(impl_integer_vector_entrywise_shr_round_unsigned);
147
148macro_rules! impl_integer_vector_entrywise_shr_round_signed {
149    ($t:ident) => {
150        impl EntrywiseShrRound<$t> for IntegerVector {
151            type Output = IntegerVector;
152
153            /// Right-shifts an [`IntegerVector`] (divides or multiplies it by a power of 2), taking
154            /// it by value, and rounds every element according to the specified rounding mode.
155            ///
156            /// Each element is rounded as by
157            /// [`ShrRound`](malachite_base::num::arithmetic::traits::ShrRound), but no
158            /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
159            /// elements may be rounded in different directions. Passing `Floor` is equivalent to
160            /// using `>>`.
161            ///
162            /// A negative `bits` shifts left, multiplying every element by $2^{-k}$; no rounding is
163            /// needed then.
164            ///
165            /// $f(v, k, r)_i = \operatorname{round}(v_i/2^k)$, where $\operatorname{round}$ rounds
166            /// according to `rm`.
167            ///
168            /// # Worst-case complexity
169            /// $T(n, m, k) = O(n + km)$
170            ///
171            /// $M(n, m, k) = O(n + km)$
172            ///
173            /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the
174            /// elements, $m$ is `bits.unsigned_abs()`, and $k$ is `self.dimension()`.
175            ///
176            /// # Panics
177            /// Panics if `rm` is `Exact` and some element is not divisible by $2^k$.
178            ///
179            /// # Examples
180            /// See [here](super::entrywise_shr_round#entrywise_shr_round).
181            #[inline]
182            fn entrywise_shr_round(mut self, bits: $t, rm: RoundingMode) -> IntegerVector {
183                self.entrywise_shr_round_assign(bits, rm);
184                self
185            }
186        }
187
188        impl EntrywiseShrRound<$t> for &IntegerVector {
189            type Output = IntegerVector;
190
191            /// Right-shifts an [`IntegerVector`] (divides or multiplies it by a power of 2), taking
192            /// it by reference, and rounds every element according to the specified rounding mode.
193            ///
194            /// Each element is rounded as by
195            /// [`ShrRound`](malachite_base::num::arithmetic::traits::ShrRound), but no
196            /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
197            /// elements may be rounded in different directions. Passing `Floor` is equivalent to
198            /// using `>>`.
199            ///
200            /// A negative `bits` shifts left, multiplying every element by $2^{-k}$; no rounding is
201            /// needed then.
202            ///
203            /// $f(v, k, r)_i = \operatorname{round}(v_i/2^k)$, where $\operatorname{round}$ rounds
204            /// according to `rm`.
205            ///
206            /// # Worst-case complexity
207            /// $T(n, m, k) = O(n + km)$
208            ///
209            /// $M(n, m, k) = O(n + km)$
210            ///
211            /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the
212            /// elements, $m$ is `bits.unsigned_abs()`, and $k$ is `self.dimension()`.
213            ///
214            /// # Panics
215            /// Panics if `rm` is `Exact` and some element is not divisible by $2^k$.
216            ///
217            /// # Examples
218            /// See [here](super::entrywise_shr_round#entrywise_shr_round).
219            #[inline]
220            fn entrywise_shr_round(self, bits: $t, rm: RoundingMode) -> IntegerVector {
221                entrywise_shr_round_ref(self, bits, rm)
222            }
223        }
224
225        impl EntrywiseShrRoundAssign<$t> for IntegerVector {
226            /// Right-shifts an [`IntegerVector`] (divides or multiplies it by a power of 2), in
227            /// place, and rounds every element according to the specified rounding mode.
228            ///
229            /// Each element is rounded as by
230            /// [`ShrRound`](malachite_base::num::arithmetic::traits::ShrRound), but no
231            /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
232            /// elements may be rounded in different directions. Passing `Floor` is equivalent to
233            /// using `>>`.
234            ///
235            /// A negative `bits` shifts left, multiplying every element by $2^{-k}$; no rounding is
236            /// needed then.
237            ///
238            /// $v_i \gets \operatorname{round}(v_i/2^k)$, where $\operatorname{round}$ rounds
239            /// according to `rm`.
240            ///
241            /// # Worst-case complexity
242            /// $T(n, m, k) = O(n + km)$
243            ///
244            /// $M(n, m, k) = O(n + km)$
245            ///
246            /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the
247            /// elements, $m$ is `bits.unsigned_abs()`, and $k$ is `self.dimension()`.
248            ///
249            /// # Panics
250            /// Panics if `rm` is `Exact` and some element is not divisible by $2^k$.
251            ///
252            /// # Examples
253            /// See [here](super::entrywise_shr_round#entrywise_shr_round_assign).
254            #[inline]
255            fn entrywise_shr_round_assign(&mut self, bits: $t, rm: RoundingMode) {
256                entrywise_shr_round_assign(self, bits, rm);
257            }
258        }
259    };
260}
261apply_to_signeds!(impl_integer_vector_entrywise_shr_round_signed);