malachite_base/unsigned_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::num::arithmetic::traits::{EntrywiseShrRound, EntrywiseShrRoundAssign};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::rounding_modes::RoundingMode;
12use crate::unsigned_vector::UnsignedVector;
13
14macro_rules! impl_entrywise_shr_round_unsigned {
15 ($t:ident) => {
16 impl<T: PrimitiveUnsigned> EntrywiseShrRound<$t> for UnsignedVector<T> {
17 type Output = UnsignedVector<T>;
18
19 /// Right-shifts an [`UnsignedVector`] (divides it by a power of 2), taking it by value,
20 /// and rounds every element according to the specified rounding mode.
21 ///
22 /// Each element is rounded as by
23 /// [`ShrRound`](crate::num::arithmetic::traits::ShrRound), but no
24 /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
25 /// elements may be rounded in different directions. Passing `Floor` or `Down` is
26 /// equivalent to using `>>`. If `bits` is at least `T::WIDTH`, every element rounds to
27 /// 0 or 1.
28 ///
29 /// $f(v, k, r)_i = \operatorname{round}(v_i/2^k)$, where $\operatorname{round}$ rounds
30 /// according to `rm`.
31 ///
32 /// # Worst-case complexity
33 /// $T(n) = O(n)$
34 ///
35 /// $M(n) = O(1)$
36 ///
37 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
38 ///
39 /// # Panics
40 /// Panics if `rm` is `Exact` and some element is not divisible by $2^k$.
41 ///
42 /// # Examples
43 /// See [here](super::entrywise_shr_round#entrywise_shr_round).
44 #[inline]
45 fn entrywise_shr_round(mut self, bits: $t, rm: RoundingMode) -> UnsignedVector<T> {
46 self.entrywise_shr_round_assign(bits, rm);
47 self
48 }
49 }
50
51 impl<T: PrimitiveUnsigned> EntrywiseShrRound<$t> for &UnsignedVector<T> {
52 type Output = UnsignedVector<T>;
53
54 /// Right-shifts an [`UnsignedVector`] (divides it by a power of 2), taking it by
55 /// reference, and rounds every element according to the specified rounding mode.
56 ///
57 /// Each element is rounded as by
58 /// [`ShrRound`](crate::num::arithmetic::traits::ShrRound), but no
59 /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
60 /// elements may be rounded in different directions. Passing `Floor` or `Down` is
61 /// equivalent to using `>>`. If `bits` is at least `T::WIDTH`, every element rounds to
62 /// 0 or 1.
63 ///
64 /// $f(v, k, r)_i = \operatorname{round}(v_i/2^k)$, where $\operatorname{round}$ rounds
65 /// according to `rm`.
66 ///
67 /// # Worst-case complexity
68 /// $T(n) = O(n)$
69 ///
70 /// $M(n) = O(n)$
71 ///
72 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
73 ///
74 /// # Panics
75 /// Panics if `rm` is `Exact` and some element is not divisible by $2^k$.
76 ///
77 /// # Examples
78 /// See [here](super::entrywise_shr_round#entrywise_shr_round).
79 fn entrywise_shr_round(self, bits: $t, rm: RoundingMode) -> UnsignedVector<T> {
80 UnsignedVector {
81 elements: self
82 .elements
83 .iter()
84 .map(|&x| x.shr_round(bits, rm).0)
85 .collect(),
86 }
87 }
88 }
89
90 impl<T: PrimitiveUnsigned> EntrywiseShrRoundAssign<$t> for UnsignedVector<T> {
91 /// Right-shifts an [`UnsignedVector`] (divides it by a power of 2), in place, and
92 /// rounds every element according to the specified rounding mode.
93 ///
94 /// Each element is rounded as by
95 /// [`ShrRound`](crate::num::arithmetic::traits::ShrRound), but no
96 /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
97 /// elements may be rounded in different directions. Passing `Floor` or `Down` is
98 /// equivalent to using `>>`. If `bits` is at least `T::WIDTH`, every element rounds to
99 /// 0 or 1.
100 ///
101 /// $v_i \gets \operatorname{round}(v_i/2^k)$, where $\operatorname{round}$ rounds
102 /// according to `rm`.
103 ///
104 /// # Worst-case complexity
105 /// $T(n) = O(n)$
106 ///
107 /// $M(n) = O(1)$
108 ///
109 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
110 ///
111 /// # Panics
112 /// Panics if `rm` is `Exact` and some element is not divisible by $2^k$.
113 ///
114 /// # Examples
115 /// See [here](super::entrywise_shr_round#entrywise_shr_round_assign).
116 fn entrywise_shr_round_assign(&mut self, bits: $t, rm: RoundingMode) {
117 for x in &mut self.elements {
118 x.shr_round_assign(bits, rm);
119 }
120 }
121 }
122 };
123}
124apply_to_unsigneds!(impl_entrywise_shr_round_unsigned);