Skip to main content

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