malachite_nz/integer_vector/arithmetic/entrywise_shl_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 EntrywiseShlRound, EntrywiseShlRoundAssign, ShlRound, ShlRoundAssign,
13};
14use malachite_base::rounding_modes::RoundingMode;
15
16// Shifts every element left by `bits`, rounding each according to `rm`.
17fn entrywise_shl_round_ref<T: Copy>(v: &IntegerVector, bits: T, rm: RoundingMode) -> IntegerVector
18where
19 for<'a> &'a Integer: ShlRound<T, Output = Integer>,
20{
21 IntegerVector {
22 elements: v.elements.iter().map(|x| x.shl_round(bits, rm).0).collect(),
23 }
24}
25
26// Shifts every element left by `bits`, rounding each according to `rm`, in place.
27fn entrywise_shl_round_assign<T: Copy>(v: &mut IntegerVector, bits: T, rm: RoundingMode)
28where
29 Integer: ShlRoundAssign<T>,
30{
31 for x in &mut v.elements {
32 x.shl_round_assign(bits, rm);
33 }
34}
35
36macro_rules! impl_integer_vector_entrywise_shl_round_signed {
37 ($t:ident) => {
38 impl EntrywiseShlRound<$t> for IntegerVector {
39 type Output = IntegerVector;
40
41 /// Left-shifts an [`IntegerVector`] (multiplies or divides it by a power of 2), taking
42 /// it by value, and rounds every element according to the specified rounding mode.
43 ///
44 /// Each element is rounded as by
45 /// [`ShlRound`](malachite_base::num::arithmetic::traits::ShlRound), 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 /// Rounding might only be necessary if `bits` is negative.
51 ///
52 /// $f(v, k, r)_i = \operatorname{round}(2^kv_i)$, where $\operatorname{round}$ rounds
53 /// according to `rm`.
54 ///
55 /// # Worst-case complexity
56 /// $T(n, m, k) = O(n + km)$
57 ///
58 /// $M(n, m, k) = O(n + km)$
59 ///
60 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the
61 /// elements, $m$ is `bits.unsigned_abs()`, and $k$ is `self.dimension()`.
62 ///
63 /// # Panics
64 /// Panics if `rm` is `Exact`, `bits` is negative, and some element is not divisible by
65 /// $2^{-k}$.
66 ///
67 /// # Examples
68 /// See [here](super::entrywise_shl_round#entrywise_shl_round).
69 #[inline]
70 fn entrywise_shl_round(mut self, bits: $t, rm: RoundingMode) -> IntegerVector {
71 self.entrywise_shl_round_assign(bits, rm);
72 self
73 }
74 }
75
76 impl EntrywiseShlRound<$t> for &IntegerVector {
77 type Output = IntegerVector;
78
79 /// Left-shifts an [`IntegerVector`] (multiplies or divides it by a power of 2), taking
80 /// it by reference, and rounds every element according to the specified rounding mode.
81 ///
82 /// Each element is rounded as by
83 /// [`ShlRound`](malachite_base::num::arithmetic::traits::ShlRound), but no
84 /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
85 /// elements may be rounded in different directions. Passing `Floor` is equivalent to
86 /// using `<<`.
87 ///
88 /// Rounding might only be necessary if `bits` is negative.
89 ///
90 /// $f(v, k, r)_i = \operatorname{round}(2^kv_i)$, where $\operatorname{round}$ rounds
91 /// according to `rm`.
92 ///
93 /// # Worst-case complexity
94 /// $T(n, m, k) = O(n + km)$
95 ///
96 /// $M(n, m, k) = O(n + km)$
97 ///
98 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the
99 /// elements, $m$ is `bits.unsigned_abs()`, and $k$ is `self.dimension()`.
100 ///
101 /// # Panics
102 /// Panics if `rm` is `Exact`, `bits` is negative, and some element is not divisible by
103 /// $2^{-k}$.
104 ///
105 /// # Examples
106 /// See [here](super::entrywise_shl_round#entrywise_shl_round).
107 #[inline]
108 fn entrywise_shl_round(self, bits: $t, rm: RoundingMode) -> IntegerVector {
109 entrywise_shl_round_ref(self, bits, rm)
110 }
111 }
112
113 impl EntrywiseShlRoundAssign<$t> for IntegerVector {
114 /// Left-shifts an [`IntegerVector`] (multiplies or divides it by a power of 2), in
115 /// place, and rounds every element according to the specified rounding mode.
116 ///
117 /// Each element is rounded as by
118 /// [`ShlRound`](malachite_base::num::arithmetic::traits::ShlRound), but no
119 /// [`Ordering`](core::cmp::Ordering) is returned, since with `Nearest` different
120 /// elements may be rounded in different directions. Passing `Floor` is equivalent to
121 /// using `<<`.
122 ///
123 /// Rounding might only be necessary if `bits` is negative.
124 ///
125 /// $v_i \gets \operatorname{round}(2^kv_i)$, where $\operatorname{round}$ rounds
126 /// according to `rm`.
127 ///
128 /// # Worst-case complexity
129 /// $T(n, m, k) = O(n + km)$
130 ///
131 /// $M(n, m, k) = O(n + km)$
132 ///
133 /// where $T$ is time, $M$ is additional memory, $n$ is the total number of bits of the
134 /// elements, $m$ is `bits.unsigned_abs()`, and $k$ is `self.dimension()`.
135 ///
136 /// # Panics
137 /// Panics if `rm` is `Exact`, `bits` is negative, and some element is not divisible by
138 /// $2^{-k}$.
139 ///
140 /// # Examples
141 /// See [here](super::entrywise_shl_round#entrywise_shl_round_assign).
142 #[inline]
143 fn entrywise_shl_round_assign(&mut self, bits: $t, rm: RoundingMode) {
144 entrywise_shl_round_assign(self, bits, rm);
145 }
146 }
147 };
148}
149apply_to_signeds!(impl_integer_vector_entrywise_shl_round_signed);