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}