Skip to main content

malachite_nz/integer_polynomial/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::integer_polynomial::IntegerPolynomial;
10use crate::natural_polynomial::NaturalPolynomial;
11use alloc::vec::Vec;
12use malachite_base::num::arithmetic::traits::{ModPowerOf2, RemPowerOf2, RemPowerOf2Assign};
13use malachite_base::polynomial::Polynomial;
14
15impl ModPowerOf2 for IntegerPolynomial {
16    type Output = NaturalPolynomial;
17
18    /// Divides every coefficient of an [`IntegerPolynomial`] by $2^k$, keeping the remainders as a
19    /// [`NaturalPolynomial`], taking the polynomial by value.
20    ///
21    /// Each remainder is non-negative, as with [`ModPowerOf2`] for
22    /// [`Integer`](crate::integer::Integer): a negative coefficient $c$ becomes $2^k - (-c \bmod
23    /// 2^k)$ unless it is a multiple of $2^k$. So the result has natural coefficients, and is
24    /// reduced modulo $2^k$, which is to say that [`mod_power_of_2_is_reduced`](
25    /// malachite_base::num::arithmetic::traits::ModPowerOf2IsReduced::mod_power_of_2_is_reduced)
26    /// returns `true` for it.
27    ///
28    /// Reducing can lower the degree, and can even give the zero polynomial: a leading coefficient
29    /// that is a multiple of $2^k$ becomes zero, and a polynomial does not hold trailing zero
30    /// coefficients. So $-4x^2 + 3$ modulo $4$ is the constant $3$.
31    ///
32    /// $$
33    /// f(p, k) = q, \quad \text{where} \quad q_i = p_i - 2^k \left \lfloor \frac{p_i}{2^k}
34    /// \right \rfloor.
35    /// $$
36    ///
37    /// # Worst-case complexity
38    /// $T(n) = O(n)$
39    ///
40    /// $M(n) = O(n)$
41    ///
42    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
43    /// coefficients.
44    ///
45    /// # Examples
46    /// ```
47    /// use core::str::FromStr;
48    /// use malachite_base::num::arithmetic::traits::ModPowerOf2;
49    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
50    ///
51    /// // Every coefficient is taken modulo 4, and negative ones become non-negative.
52    /// assert_eq!(
53    ///     IntegerPolynomial::from_str("x^2-3*x-2")
54    ///         .unwrap()
55    ///         .mod_power_of_2(2)
56    ///         .to_string(),
57    ///     "x^2+x+2"
58    /// );
59    ///
60    /// // Reducing the leading coefficient to zero lowers the degree.
61    /// assert_eq!(
62    ///     IntegerPolynomial::from_str("-4*x^2+3")
63    ///         .unwrap()
64    ///         .mod_power_of_2(2)
65    ///         .to_string(),
66    ///     "3"
67    /// );
68    /// ```
69    #[inline]
70    fn mod_power_of_2(self, pow: u64) -> NaturalPolynomial {
71        // `from_coefficients_asc` trims, which is what makes the degree fall when the leading
72        // coefficient reduces to zero.
73        NaturalPolynomial::from_coefficients_asc(
74            self.coefficients
75                .into_iter()
76                .map(|c| c.mod_power_of_2(pow))
77                .collect::<Vec<_>>(),
78        )
79    }
80}
81
82impl ModPowerOf2 for &IntegerPolynomial {
83    type Output = NaturalPolynomial;
84
85    /// Divides every coefficient of an [`IntegerPolynomial`] by $2^k$, keeping the remainders as a
86    /// [`NaturalPolynomial`], taking the polynomial by reference.
87    ///
88    /// See the documentation for the [`ModPowerOf2`] implementation on [`IntegerPolynomial`] for
89    /// details, including how negative coefficients are handled and how reducing can lower the
90    /// degree.
91    ///
92    /// # Worst-case complexity
93    /// $T(n) = O(n)$
94    ///
95    /// $M(n) = O(n)$
96    ///
97    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
98    /// coefficients.
99    ///
100    /// # Examples
101    /// ```
102    /// use core::str::FromStr;
103    /// use malachite_base::num::arithmetic::traits::ModPowerOf2;
104    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
105    ///
106    /// // Every coefficient is taken modulo 4, and negative ones become non-negative.
107    /// assert_eq!(
108    ///     (&IntegerPolynomial::from_str("x^2-3*x-2").unwrap())
109    ///         .mod_power_of_2(2)
110    ///         .to_string(),
111    ///     "x^2+x+2"
112    /// );
113    ///
114    /// // Reducing the leading coefficient to zero lowers the degree.
115    /// assert_eq!(
116    ///     (&IntegerPolynomial::from_str("-4*x^2+3").unwrap())
117    ///         .mod_power_of_2(2)
118    ///         .to_string(),
119    ///     "3"
120    /// );
121    /// ```
122    #[inline]
123    fn mod_power_of_2(self, pow: u64) -> NaturalPolynomial {
124        NaturalPolynomial::from_coefficients_asc(
125            self.coefficients
126                .iter()
127                .map(|c| c.mod_power_of_2(pow))
128                .collect::<Vec<_>>(),
129        )
130    }
131}
132
133impl RemPowerOf2 for IntegerPolynomial {
134    type Output = Self;
135
136    /// Divides every coefficient of an [`IntegerPolynomial`] by $2^k$, keeping the remainders,
137    /// taking the polynomial by value.
138    ///
139    /// Each remainder has the sign of its coefficient and a smaller absolute value than $2^k$, as
140    /// with [`RemPowerOf2`] for [`Integer`](crate::integer::Integer)s. This is the remainder of
141    /// truncating division, and the result stays an [`IntegerPolynomial`]; for a remainder that is
142    /// always non-negative, and a [`NaturalPolynomial`] result, use [`ModPowerOf2`].
143    ///
144    /// Reducing can lower the degree, and can even give the zero polynomial: a leading coefficient
145    /// that is a multiple of $2^k$ becomes zero, and a polynomial does not hold trailing zero
146    /// coefficients. So $-4x^2 - 3$ modulo $4$ is the constant $-3$.
147    ///
148    /// $$
149    /// f(p, k) = r, \quad \text{where} \quad r_i = p_i - 2^k \operatorname{sgn}(p_i)
150    ///     \left \lfloor \frac{|p_i|}{2^k} \right \rfloor.
151    /// $$
152    ///
153    /// # Worst-case complexity
154    /// $T(n) = O(n)$
155    ///
156    /// $M(n) = O(1)$
157    ///
158    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
159    /// coefficients.
160    ///
161    /// # Examples
162    /// ```
163    /// use core::str::FromStr;
164    /// use malachite_base::num::arithmetic::traits::RemPowerOf2;
165    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
166    ///
167    /// // Every coefficient is taken modulo 4, keeping its sign.
168    /// assert_eq!(
169    ///     IntegerPolynomial::from_str("x^2-7*x-2")
170    ///         .unwrap()
171    ///         .rem_power_of_2(2)
172    ///         .to_string(),
173    ///     "x^2-3*x-2"
174    /// );
175    ///
176    /// // Reducing the leading coefficient to zero lowers the degree.
177    /// assert_eq!(
178    ///     IntegerPolynomial::from_str("-4*x^2-3")
179    ///         .unwrap()
180    ///         .rem_power_of_2(2)
181    ///         .to_string(),
182    ///     "-3"
183    /// );
184    /// ```
185    #[inline]
186    fn rem_power_of_2(mut self, pow: u64) -> Self {
187        self.rem_power_of_2_assign(pow);
188        self
189    }
190}
191
192impl RemPowerOf2 for &IntegerPolynomial {
193    type Output = IntegerPolynomial;
194
195    /// Divides every coefficient of an [`IntegerPolynomial`] by $2^k$, keeping the remainders,
196    /// taking the polynomial by reference.
197    ///
198    /// See the documentation for the [`RemPowerOf2`] implementation on [`IntegerPolynomial`] for
199    /// details, including the signs of the remainders and how reducing can lower the degree.
200    ///
201    /// # Worst-case complexity
202    /// $T(n) = O(n)$
203    ///
204    /// $M(n) = O(n)$
205    ///
206    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
207    /// coefficients.
208    ///
209    /// # Examples
210    /// ```
211    /// use core::str::FromStr;
212    /// use malachite_base::num::arithmetic::traits::RemPowerOf2;
213    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
214    ///
215    /// // Every coefficient is taken modulo 4, keeping its sign.
216    /// assert_eq!(
217    ///     (&IntegerPolynomial::from_str("x^2-7*x-2").unwrap())
218    ///         .rem_power_of_2(2)
219    ///         .to_string(),
220    ///     "x^2-3*x-2"
221    /// );
222    ///
223    /// // Reducing the leading coefficient to zero lowers the degree.
224    /// assert_eq!(
225    ///     (&IntegerPolynomial::from_str("-4*x^2-3").unwrap())
226    ///         .rem_power_of_2(2)
227    ///         .to_string(),
228    ///     "-3"
229    /// );
230    /// ```
231    #[inline]
232    fn rem_power_of_2(self, pow: u64) -> IntegerPolynomial {
233        // `from_coefficients_asc` trims, which is what makes the degree fall when the leading
234        // coefficient reduces to zero.
235        IntegerPolynomial::from_coefficients_asc(
236            self.coefficients
237                .iter()
238                .map(|c| c.rem_power_of_2(pow))
239                .collect::<Vec<_>>(),
240        )
241    }
242}
243
244impl RemPowerOf2Assign for IntegerPolynomial {
245    /// Divides every coefficient of an [`IntegerPolynomial`] by $2^k$, replacing the polynomial by
246    /// the one whose coefficients are the remainders.
247    ///
248    /// See the documentation for the [`RemPowerOf2`] implementation on [`IntegerPolynomial`] for
249    /// details, including the signs of the remainders and how reducing can lower the degree.
250    ///
251    /// # Worst-case complexity
252    /// $T(n) = O(n)$
253    ///
254    /// $M(n) = O(1)$
255    ///
256    /// where $T$ is time, $M$ is additional memory, and $n$ is the total number of bits of the
257    /// coefficients.
258    ///
259    /// # Examples
260    /// ```
261    /// use core::str::FromStr;
262    /// use malachite_base::num::arithmetic::traits::RemPowerOf2Assign;
263    /// use malachite_nz::integer_polynomial::IntegerPolynomial;
264    ///
265    /// let mut p = IntegerPolynomial::from_str("x^2-7*x-2").unwrap();
266    /// p.rem_power_of_2_assign(2);
267    /// assert_eq!(p.to_string(), "x^2-3*x-2");
268    ///
269    /// let mut p = IntegerPolynomial::from_str("-4*x^2-3").unwrap();
270    /// p.rem_power_of_2_assign(2);
271    /// assert_eq!(p.to_string(), "-3");
272    /// ```
273    fn rem_power_of_2_assign(&mut self, pow: u64) {
274        for c in &mut self.coefficients {
275            c.rem_power_of_2_assign(pow);
276        }
277        self.trim();
278    }
279}