malachite_q/arithmetic/pow.rs
1// Copyright © 2025 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::Rational;
10use malachite_base::num::arithmetic::traits::{
11 Parity, Pow, PowAssign, Reciprocal, ReciprocalAssign,
12};
13
14impl Pow<u64> for Rational {
15 type Output = Self;
16
17 /// Raises a [`Rational`] to a power, taking the [`Rational`] by value.
18 ///
19 /// $f(x, n) = x^n$.
20 ///
21 /// # Worst-case complexity
22 /// $T(n, m) = O(nm \log (nm) \log\log (nm))$
23 ///
24 /// $M(n, m) = O(nm \log (nm))$
25 ///
26 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and $m$ is
27 /// `exp`.
28 ///
29 /// # Examples
30 /// ```
31 /// use malachite_base::num::arithmetic::traits::Pow;
32 /// use malachite_q::Rational;
33 ///
34 /// assert_eq!(
35 /// Rational::from_signeds(22, 7).pow(3u64).to_string(),
36 /// "10648/343"
37 /// );
38 /// assert_eq!(
39 /// Rational::from_signeds(-22, 7).pow(3u64).to_string(),
40 /// "-10648/343"
41 /// );
42 /// assert_eq!(
43 /// Rational::from_signeds(-22, 7).pow(4u64).to_string(),
44 /// "234256/2401"
45 /// );
46 /// ```
47 #[inline]
48 fn pow(mut self, exp: u64) -> Self {
49 self.pow_assign(exp);
50 self
51 }
52}
53
54impl Pow<u64> for &Rational {
55 type Output = Rational;
56
57 /// Raises a [`Rational`] to a power, taking the [`Rational`] by reference.
58 ///
59 /// $f(x, n) = x^n$.
60 ///
61 /// # Worst-case complexity
62 /// $T(n, m) = O(nm \log (nm) \log\log (nm))$
63 ///
64 /// $M(n, m) = O(nm \log (nm))$
65 ///
66 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and $m$ is
67 /// `exp`.
68 ///
69 /// # Examples
70 /// ```
71 /// use malachite_base::num::arithmetic::traits::Pow;
72 /// use malachite_q::Rational;
73 ///
74 /// assert_eq!(
75 /// (&Rational::from_signeds(22, 7)).pow(3u64).to_string(),
76 /// "10648/343"
77 /// );
78 /// assert_eq!(
79 /// (&Rational::from_signeds(-22, 7)).pow(3u64).to_string(),
80 /// "-10648/343"
81 /// );
82 /// assert_eq!(
83 /// (&Rational::from_signeds(-22, 7)).pow(4u64).to_string(),
84 /// "234256/2401"
85 /// );
86 /// ```
87 #[inline]
88 fn pow(self, exp: u64) -> Rational {
89 Rational {
90 sign: self.sign || exp.even(),
91 numerator: (&self.numerator).pow(exp),
92 denominator: (&self.denominator).pow(exp),
93 }
94 }
95}
96
97impl PowAssign<u64> for Rational {
98 /// Raises a [`Rational`] to a power in place.
99 ///
100 /// $x \gets x^n$.
101 ///
102 /// # Worst-case complexity
103 /// $T(n, m) = O(nm \log (nm) \log\log (nm))$
104 ///
105 /// $M(n, m) = O(nm \log (nm))$
106 ///
107 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and $m$ is
108 /// `exp`.
109 ///
110 /// # Examples
111 /// ```
112 /// use malachite_base::num::arithmetic::traits::PowAssign;
113 /// use malachite_q::Rational;
114 ///
115 /// let mut x = Rational::from_signeds(22, 7);
116 /// x.pow_assign(3u64);
117 /// assert_eq!(x.to_string(), "10648/343");
118 ///
119 /// let mut x = Rational::from_signeds(-22, 7);
120 /// x.pow_assign(3u64);
121 /// assert_eq!(x.to_string(), "-10648/343");
122 ///
123 /// let mut x = Rational::from_signeds(22, 7);
124 /// x.pow_assign(4u64);
125 /// assert_eq!(x.to_string(), "234256/2401");
126 /// ```
127 fn pow_assign(&mut self, exp: u64) {
128 self.sign |= exp.even();
129 self.numerator.pow_assign(exp);
130 self.denominator.pow_assign(exp);
131 }
132}
133
134impl Pow<i64> for Rational {
135 type Output = Self;
136
137 /// Raises a [`Rational`] to a power, taking the [`Rational`] by value.
138 ///
139 /// $f(x, n) = x^n$.
140 ///
141 /// # Worst-case complexity
142 /// $T(n, m) = O(nm \log (nm) \log\log (nm))$
143 ///
144 /// $M(n, m) = O(nm \log (nm))$
145 ///
146 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and $m$ is
147 /// `exp.abs()`.
148 ///
149 /// # Panics
150 /// Panics if `self` is zero and `exp` is negative.
151 ///
152 /// # Examples
153 /// ```
154 /// use malachite_base::num::arithmetic::traits::Pow;
155 /// use malachite_q::Rational;
156 ///
157 /// assert_eq!(
158 /// Rational::from_signeds(22, 7).pow(3i64).to_string(),
159 /// "10648/343"
160 /// );
161 /// assert_eq!(
162 /// Rational::from_signeds(-22, 7).pow(3i64).to_string(),
163 /// "-10648/343"
164 /// );
165 /// assert_eq!(
166 /// Rational::from_signeds(-22, 7).pow(4i64).to_string(),
167 /// "234256/2401"
168 /// );
169 /// assert_eq!(
170 /// Rational::from_signeds(22, 7).pow(-3i64).to_string(),
171 /// "343/10648"
172 /// );
173 /// assert_eq!(
174 /// Rational::from_signeds(-22, 7).pow(-3i64).to_string(),
175 /// "-343/10648"
176 /// );
177 /// assert_eq!(
178 /// Rational::from_signeds(-22, 7).pow(-4i64).to_string(),
179 /// "2401/234256"
180 /// );
181 /// ```
182 #[inline]
183 fn pow(mut self, exp: i64) -> Self {
184 self.pow_assign(exp);
185 self
186 }
187}
188
189impl Pow<i64> for &Rational {
190 type Output = Rational;
191
192 /// Raises a [`Rational`] to a power, taking the [`Rational`] by reference.
193 ///
194 /// $f(x, n) = x^n$.
195 ///
196 /// # Worst-case complexity
197 /// $T(n, m) = O(nm \log (nm) \log\log (nm))$
198 ///
199 /// $M(n, m) = O(nm \log (nm))$
200 ///
201 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and $m$ is
202 /// `exp.abs()`.
203 ///
204 /// # Panics
205 /// Panics if `self` is zero and `exp` is negative.
206 ///
207 /// # Examples
208 /// ```
209 /// use malachite_base::num::arithmetic::traits::Pow;
210 /// use malachite_q::Rational;
211 ///
212 /// assert_eq!(
213 /// (&Rational::from_signeds(22, 7)).pow(3i64).to_string(),
214 /// "10648/343"
215 /// );
216 /// assert_eq!(
217 /// (&Rational::from_signeds(-22, 7)).pow(3i64).to_string(),
218 /// "-10648/343"
219 /// );
220 /// assert_eq!(
221 /// (&Rational::from_signeds(-22, 7)).pow(4i64).to_string(),
222 /// "234256/2401"
223 /// );
224 /// assert_eq!(
225 /// (&Rational::from_signeds(22, 7)).pow(-3i64).to_string(),
226 /// "343/10648"
227 /// );
228 /// assert_eq!(
229 /// (&Rational::from_signeds(-22, 7)).pow(-3i64).to_string(),
230 /// "-343/10648"
231 /// );
232 /// assert_eq!(
233 /// (&Rational::from_signeds(-22, 7)).pow(-4i64).to_string(),
234 /// "2401/234256"
235 /// );
236 /// ```
237 #[inline]
238 fn pow(self, exp: i64) -> Rational {
239 let abs_exp = exp.unsigned_abs();
240 if exp >= 0 {
241 self.pow(abs_exp)
242 } else {
243 self.pow(abs_exp).reciprocal()
244 }
245 }
246}
247
248impl PowAssign<i64> for Rational {
249 /// Raises a [`Rational`] to a power in place.
250 ///
251 /// $x \gets x^n$.
252 ///
253 /// # Worst-case complexity
254 /// $T(n, m) = O(nm \log (nm) \log\log (nm))$
255 ///
256 /// $M(n, m) = O(nm \log (nm))$
257 ///
258 /// where $T$ is time, $M$ is additional memory, $n$ is `self.significant_bits()`, and $m$ is
259 /// `exp.abs()`.
260 ///
261 /// # Panics
262 /// Panics if `self` is zero and `exp` is negative.
263 ///
264 /// # Examples
265 /// ```
266 /// use malachite_base::num::arithmetic::traits::PowAssign;
267 /// use malachite_q::Rational;
268 ///
269 /// let mut x = Rational::from_signeds(22, 7);
270 /// x.pow_assign(3i64);
271 /// assert_eq!(x.to_string(), "10648/343");
272 ///
273 /// let mut x = Rational::from_signeds(-22, 7);
274 /// x.pow_assign(3i64);
275 /// assert_eq!(x.to_string(), "-10648/343");
276 ///
277 /// let mut x = Rational::from_signeds(22, 7);
278 /// x.pow_assign(4i64);
279 /// assert_eq!(x.to_string(), "234256/2401");
280 ///
281 /// let mut x = Rational::from_signeds(22, 7);
282 /// x.pow_assign(-3i64);
283 /// assert_eq!(x.to_string(), "343/10648");
284 ///
285 /// let mut x = Rational::from_signeds(-22, 7);
286 /// x.pow_assign(-3i64);
287 /// assert_eq!(x.to_string(), "-343/10648");
288 ///
289 /// let mut x = Rational::from_signeds(22, 7);
290 /// x.pow_assign(-4i64);
291 /// assert_eq!(x.to_string(), "2401/234256");
292 /// ```
293 fn pow_assign(&mut self, exp: i64) {
294 let abs_exp = exp.unsigned_abs();
295 if exp >= 0 {
296 self.pow_assign(abs_exp);
297 } else {
298 self.pow_assign(abs_exp);
299 self.reciprocal_assign();
300 }
301 }
302}