Skip to main content

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