Skip to main content

malachite_nz/integer/factorization/
remove_power.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 malachite_base::num::arithmetic::traits::Parity;
11use malachite_base::num::factorization::traits::{RemovePower, RemovePowerAssign};
12
13// How many times a factor divides a value depends only on the magnitudes, and the quotient is the
14// exact division by the signed power: it is negative when the value is, and flips again when the
15// factor is negative and the power is odd.
16fn remove_power_helper(x: &Integer, y: &Integer) -> (Integer, u64) {
17    let (abs, k) = x.unsigned_abs_ref().remove_power(y.unsigned_abs_ref());
18    let negative = (*x < 0) != (*y < 0 && k.odd());
19    (Integer::from_sign_and_abs(!negative, abs), k)
20}
21
22impl RemovePower<Self> for Integer {
23    type Output = Self;
24
25    /// Removes the largest power of a factor from an [`Integer`], returning the reduced [`Integer`]
26    /// together with the exponent of that power, and taking both [`Integer`]s by value.
27    ///
28    /// If $f^k$ is the largest power of `other` that divides `self`, this returns
29    /// $(\text{self}/f^k, k)$, so a negative factor raised to an odd power flips the sign of the
30    /// quotient. The factor need not be prime. Zero is left alone, with an exponent of 0, since
31    /// every power of the factor divides it.
32    ///
33    /// # Worst-case complexity
34    /// $T(n) = O(n (\log n)^2 \log\log n)$
35    ///
36    /// $M(n) = O(n \log n)$
37    ///
38    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
39    ///
40    /// # Panics
41    /// Panics if `other` is 0, 1, or -1.
42    ///
43    /// # Examples
44    /// See [here](super::remove_power#remove_power).
45    #[inline]
46    fn remove_power(self, other: Self) -> (Self, u64) {
47        remove_power_helper(&self, &other)
48    }
49}
50
51impl RemovePower<&Self> for Integer {
52    type Output = Self;
53
54    /// Removes the largest power of a factor from an [`Integer`], returning the reduced [`Integer`]
55    /// together with the exponent of that power, and taking the first [`Integer`] by value and the
56    /// second by reference.
57    ///
58    /// If $f^k$ is the largest power of `other` that divides `self`, this returns
59    /// $(\text{self}/f^k, k)$, so a negative factor raised to an odd power flips the sign of the
60    /// quotient. The factor need not be prime. Zero is left alone, with an exponent of 0, since
61    /// every power of the factor divides it.
62    ///
63    /// # Worst-case complexity
64    /// $T(n) = O(n (\log n)^2 \log\log n)$
65    ///
66    /// $M(n) = O(n \log n)$
67    ///
68    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
69    ///
70    /// # Panics
71    /// Panics if `other` is 0, 1, or -1.
72    ///
73    /// # Examples
74    /// See [here](super::remove_power#remove_power).
75    #[inline]
76    fn remove_power(self, other: &Self) -> (Self, u64) {
77        remove_power_helper(&self, other)
78    }
79}
80
81impl RemovePower<Integer> for &Integer {
82    type Output = Integer;
83
84    /// Removes the largest power of a factor from an [`Integer`], returning the reduced [`Integer`]
85    /// together with the exponent of that power, and taking the first [`Integer`] by reference and
86    /// the second by value.
87    ///
88    /// If $f^k$ is the largest power of `other` that divides `self`, this returns
89    /// $(\text{self}/f^k, k)$, so a negative factor raised to an odd power flips the sign of the
90    /// quotient. The factor need not be prime. Zero is left alone, with an exponent of 0, since
91    /// every power of the factor divides it.
92    ///
93    /// # Worst-case complexity
94    /// $T(n) = O(n (\log n)^2 \log\log n)$
95    ///
96    /// $M(n) = O(n \log n)$
97    ///
98    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
99    ///
100    /// # Panics
101    /// Panics if `other` is 0, 1, or -1.
102    ///
103    /// # Examples
104    /// See [here](super::remove_power#remove_power).
105    #[inline]
106    fn remove_power(self, other: Integer) -> (Integer, u64) {
107        remove_power_helper(self, &other)
108    }
109}
110
111impl RemovePower<&Integer> for &Integer {
112    type Output = Integer;
113
114    /// Removes the largest power of a factor from an [`Integer`], returning the reduced [`Integer`]
115    /// together with the exponent of that power, and taking both [`Integer`]s by reference.
116    ///
117    /// If $f^k$ is the largest power of `other` that divides `self`, this returns
118    /// $(\text{self}/f^k, k)$, so a negative factor raised to an odd power flips the sign of the
119    /// quotient. The factor need not be prime. Zero is left alone, with an exponent of 0, since
120    /// every power of the factor divides it.
121    ///
122    /// # Worst-case complexity
123    /// $T(n) = O(n (\log n)^2 \log\log n)$
124    ///
125    /// $M(n) = O(n \log n)$
126    ///
127    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
128    ///
129    /// # Panics
130    /// Panics if `other` is 0, 1, or -1.
131    ///
132    /// # Examples
133    /// See [here](super::remove_power#remove_power).
134    #[inline]
135    fn remove_power(self, other: &Integer) -> (Integer, u64) {
136        remove_power_helper(self, other)
137    }
138}
139
140impl RemovePowerAssign<Self> for Integer {
141    /// Divides an [`Integer`] by the largest power of a factor that divides it, in place, returning
142    /// the exponent of that power. The factor is taken by value.
143    ///
144    /// The factor need not be prime. Zero is left alone, with an exponent of 0.
145    ///
146    /// # Worst-case complexity
147    /// $T(n) = O(n (\log n)^2 \log\log n)$
148    ///
149    /// $M(n) = O(n \log n)$
150    ///
151    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
152    ///
153    /// # Panics
154    /// Panics if `other` is 0, 1, or -1.
155    ///
156    /// # Examples
157    /// See [here](super::remove_power#remove_power_assign).
158    #[inline]
159    fn remove_power_assign(&mut self, other: Self) -> u64 {
160        let (q, k) = remove_power_helper(self, &other);
161        *self = q;
162        k
163    }
164}
165
166impl RemovePowerAssign<&Self> for Integer {
167    /// Divides an [`Integer`] by the largest power of a factor that divides it, in place, returning
168    /// the exponent of that power. The factor is taken by reference.
169    ///
170    /// The factor need not be prime. Zero is left alone, with an exponent of 0.
171    ///
172    /// # Worst-case complexity
173    /// $T(n) = O(n (\log n)^2 \log\log n)$
174    ///
175    /// $M(n) = O(n \log n)$
176    ///
177    /// where $T$ is time, $M$ is additional memory, and $n$ is `self.significant_bits()`.
178    ///
179    /// # Panics
180    /// Panics if `other` is 0, 1, or -1.
181    ///
182    /// # Examples
183    /// See [here](super::remove_power#remove_power_assign).
184    #[inline]
185    fn remove_power_assign(&mut self, other: &Self) -> u64 {
186        let (q, k) = remove_power_helper(self, other);
187        *self = q;
188        k
189    }
190}