malachite_base/unsigned_vector/arithmetic/mod_power_of_2.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::{ModPowerOf2, ModPowerOf2Assign};
10use crate::num::basic::unsigneds::PrimitiveUnsigned;
11use crate::unsigned_vector::UnsignedVector;
12
13impl<T: PrimitiveUnsigned> ModPowerOf2 for UnsignedVector<T> {
14 type Output = Self;
15
16 /// Divides every element of an [`UnsignedVector`] by $2^k$, keeping the remainders, taking the
17 /// vector by value.
18 ///
19 /// The result is reduced modulo $2^k$, which is to say that [`mod_power_of_2_is_reduced`](
20 /// crate::num::arithmetic::traits::ModPowerOf2IsReduced::mod_power_of_2_is_reduced) returns
21 /// `true` for it. The dimension is unchanged: unlike a polynomial, a vector keeps the elements
22 /// that reduce to zero, so $(4, 3)$ modulo 4 is $(0, 3)$.
23 ///
24 /// No `T` reaches $2^W$, where $W$ is `T::WIDTH`, so for $k \geq W$ this leaves the vector
25 /// alone.
26 ///
27 /// $$
28 /// f(v, k) = w, \\quad \text{where} \\quad w_i = v_i - 2^k \left \lfloor \frac{v_i}{2^k}
29 /// \right \rfloor.
30 /// $$
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 /// # Examples
40 /// ```
41 /// use core::str::FromStr;
42 /// use malachite_base::num::arithmetic::traits::ModPowerOf2;
43 /// use malachite_base::unsigned_vector::UnsignedVector;
44 ///
45 /// // Every element is taken modulo 2.
46 /// assert_eq!(
47 /// UnsignedVector::<u64>::from_str("(1, 3, 2)")
48 /// .unwrap()
49 /// .mod_power_of_2(1)
50 /// .to_string(),
51 /// "(1, 1, 0)"
52 /// );
53 ///
54 /// // An element that reduces to zero stays, so the dimension is unchanged.
55 /// assert_eq!(
56 /// UnsignedVector::<u64>::from_str("(4, 3)")
57 /// .unwrap()
58 /// .mod_power_of_2(2)
59 /// .to_string(),
60 /// "(0, 3)"
61 /// );
62 ///
63 /// // A power at least as wide as the element type leaves the vector alone.
64 /// assert_eq!(
65 /// UnsignedVector::<u8>::from_str("(255, 1)")
66 /// .unwrap()
67 /// .mod_power_of_2(8)
68 /// .to_string(),
69 /// "(255, 1)"
70 /// );
71 /// ```
72 #[inline]
73 fn mod_power_of_2(mut self, pow: u64) -> Self {
74 self.mod_power_of_2_assign(pow);
75 self
76 }
77}
78
79impl<T: PrimitiveUnsigned> ModPowerOf2 for &UnsignedVector<T> {
80 type Output = UnsignedVector<T>;
81
82 /// Divides every element of an [`UnsignedVector`] by $2^k$, keeping the remainders, taking the
83 /// vector by reference.
84 ///
85 /// See the documentation for the [`ModPowerOf2`] implementation on [`UnsignedVector`] for
86 /// details.
87 ///
88 /// # Worst-case complexity
89 /// $T(n) = O(n)$
90 ///
91 /// $M(n) = O(n)$
92 ///
93 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
94 ///
95 /// # Examples
96 /// ```
97 /// use core::str::FromStr;
98 /// use malachite_base::num::arithmetic::traits::ModPowerOf2;
99 /// use malachite_base::unsigned_vector::UnsignedVector;
100 ///
101 /// let v = UnsignedVector::<u64>::from_str("(4, 3)").unwrap();
102 /// assert_eq!((&v).mod_power_of_2(2).to_string(), "(0, 3)");
103 /// // The vector is left alone.
104 /// assert_eq!(v.to_string(), "(4, 3)");
105 /// ```
106 #[inline]
107 fn mod_power_of_2(self, pow: u64) -> UnsignedVector<T> {
108 UnsignedVector {
109 elements: self
110 .elements
111 .iter()
112 .map(|&x| x.mod_power_of_2(pow))
113 .collect(),
114 }
115 }
116}
117
118impl<T: PrimitiveUnsigned> ModPowerOf2Assign for UnsignedVector<T> {
119 /// Divides every element of an [`UnsignedVector`] by $2^k$, replacing each element by the
120 /// remainder.
121 ///
122 /// See the documentation for the [`ModPowerOf2`] implementation on [`UnsignedVector`] for
123 /// details.
124 ///
125 /// # Worst-case complexity
126 /// $T(n) = O(n)$
127 ///
128 /// $M(n) = O(1)$
129 ///
130 /// where $T$ is time, $M$ is additional memory, and $n$ is `self.dimension()`.
131 ///
132 /// # Examples
133 /// ```
134 /// use core::str::FromStr;
135 /// use malachite_base::num::arithmetic::traits::ModPowerOf2Assign;
136 /// use malachite_base::unsigned_vector::UnsignedVector;
137 ///
138 /// let mut v = UnsignedVector::<u64>::from_str("(1, 3, 2)").unwrap();
139 /// v.mod_power_of_2_assign(1);
140 /// assert_eq!(v.to_string(), "(1, 1, 0)");
141 ///
142 /// let mut v = UnsignedVector::<u64>::from_str("(4, 3)").unwrap();
143 /// v.mod_power_of_2_assign(2);
144 /// assert_eq!(v.to_string(), "(0, 3)");
145 /// ```
146 fn mod_power_of_2_assign(&mut self, pow: u64) {
147 // A shortcut rather than a necessity: no `T` reaches its own width as a power, so a wide
148 // power is already the identity on every element.
149 if pow >= T::WIDTH {
150 return;
151 }
152 for x in &mut self.elements {
153 x.mod_power_of_2_assign(pow);
154 }
155 }
156}