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);