malachite_float/arithmetic/log_base_rational_base.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::InnerFloat::{Finite, Infinity, NaN, Zero};
10use crate::arithmetic::log_base_2::extended_log_base_2_of_rational;
11use crate::basic::extended::ExtendedFloat;
12use crate::{
13 Float, emulate_float_to_float_fn, float_either_zero, float_infinity, float_nan,
14 float_negative_infinity,
15};
16use core::cmp::Ordering::{self, *};
17use malachite_base::num::arithmetic::traits::{
18 CeilingLogBase2, CheckedLogBase, LogBase, LogBaseAssign,
19};
20use malachite_base::num::basic::floats::PrimitiveFloat;
21use malachite_base::num::basic::integers::PrimitiveInt;
22use malachite_base::num::basic::traits::Zero as ZeroTrait;
23use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
24use malachite_base::num::factorization::traits::ExpressAsPower;
25use malachite_base::num::logic::traits::SignificantBits;
26use malachite_base::rounding_modes::RoundingMode::{self, *};
27use malachite_nz::natural::arithmetic::float_extras::float_can_round;
28use malachite_nz::platform::Limb;
29use malachite_q::Rational;
30
31// Returns `Some(log_base(x))` when it is rational, and `None` when it is irrational. The input `x`
32// must be finite, positive, and not equal to 1, and `base` must be greater than 1.
33//
34// `log_base(x)` is rational exactly when `x` and `base` are both powers of a common rational `g`,
35// say `x = g^a` and `base = g^e_base`; then `log_base(x) = a / e_base`. Taking `g` to be the
36// primitive root of `base` (`base.express_as_power()`), this holds iff `x` is an integer power of
37// `g` (including a negative power when `x < 1`), found by `Rational::checked_log_base`.
38//
39// Detecting these rational results up front is essential, not just an optimization: when the result
40// is exactly representable (for example `log_9(3) = 1/2`), the Ziv loop in
41// `log_base_rational_base_prec_round_normal` would never terminate, because its rounding test
42// cannot resolve the ordering (less than, equal to, or greater than the representable value) of a
43// result sitting exactly on a representable point or tie. That holds in every rounding mode, so
44// every exactly-representable result must be caught here.
45//
46// Materializing `x` as a `Rational` is kept balloon-safe by capping `x`'s exponent and `base`'s
47// size at `bound`, the larger of `x`'s own precision and the requested `prec`. The two can differ
48// sharply -- a precision-1 `x` such as `2.0` may be asked for a 53-bit result -- so the bound must
49// track `prec`, not just `x.get_prec()`; otherwise an exactly-representable result like
50// `log_{2^64}(2) = 2^-6` would be missed and the Ziv loop would spin forever on it.
51// (`Rational::checked_log_base` itself is balloon-safe even for a `g` near 1.)
52pub(crate) fn rational_log_base_rational_base(
53 x: &Float,
54 base: &Rational,
55 prec: u64,
56) -> Option<Rational> {
57 let bound = x.get_prec().unwrap().max(prec).saturating_mul(64);
58 let e = i64::from(x.get_exponent().unwrap());
59 if e.unsigned_abs() > bound || base.significant_bits() > bound {
60 return None;
61 }
62 // `express_as_power` returns `None` when `base` is not a perfect power, in which case `base`
63 // itself is `g` (with exponent 1).
64 let (root, e_base) = base.express_as_power().unwrap_or_else(|| (base.clone(), 1));
65 let a = (&Rational::exact_from(x)).checked_log_base(&root)?;
66 Some(Rational::from_signeds(a, i64::exact_from(e_base)))
67}
68
69// The computation of log_base(x) for a `Rational` base is done by log_base(x) = log_2(x) /
70// log_2(base). The input is finite, nonzero, and positive, and `base` is greater than 1.
71//
72// `log_2(base)` is computed in the extended exponent range (see `extended_log_base_2_of_rational`)
73// so that a base near 1 -- where `log_2(base)` is tiny and would otherwise underflow an ordinary
74// `Float`, losing the operand entirely -- is represented faithfully. The quotient is also kept
75// extended, and the single conversion back to a `Float`, via `ExtendedFloat::into_float_helper`,
76// performs the one correctly-rounded clamp to an infinity/maximum or zero/minimum per the rounding
77// mode. Unlike an integer base, a `Rational` base allows both overflow (base near 1) and underflow
78// (x near 1); both are handled by that clamp. (`log_2(x)` itself never underflows: `x` is a
79// `Float`, so `|x - 1|` is at least the smallest positive `Float`, keeping `|log_2(x)|`
80// representable.)
81fn log_base_rational_base_prec_round_normal(
82 x: &Float,
83 base: &Rational,
84 prec: u64,
85 rm: RoundingMode,
86) -> (Float, Ordering) {
87 // If x is 1, the result is 0.
88 if *x == 1u32 {
89 return (Float::ZERO, Equal);
90 }
91 // If log_base(x) is rational -- x and base are both powers of a common rational -- compute it
92 // directly. This includes exactly-representable results (which the Ziv loop could never
93 // certify) as well as non-representable rationals (cheaper and exact this way).
94 if let Some(q) = rational_log_base_rational_base(x, base, prec) {
95 return Float::from_rational_prec_round(q, prec, rm);
96 }
97 // The result is irrational, so it is never exactly representable.
98 assert_ne!(rm, Exact, "Inexact log_base_rational_base");
99 // The initial slack keeps working_prec at least 7, so the working_prec - 6 below stays
100 // positive.
101 let mut working_prec = prec + 6 + prec.ceiling_log_base_2();
102 let mut increment = Limb::WIDTH;
103 loop {
104 // log_2(x), correctly rounded to working_prec; finite and nonzero (x is positive and not
105 // 1), and never underflowing, so the ordinary log wrapped as an ExtendedFloat suffices.
106 let num = ExtendedFloat::from(x.log_base_2_prec_ref(working_prec).0);
107 // log_2(base) > 0, extended (may be tiny for a base near 1).
108 let den = extended_log_base_2_of_rational(base, working_prec);
109 // log_2(x) / log_2(base) in the extended range; cannot overflow or underflow here.
110 let (quotient, _) = num.div_prec_val_ref(&den, working_prec);
111 // log_2(x) is correctly rounded (<= 1/2 ulp), log_2(base) is within 2 ulps, and the
112 // division adds at most 1 more, for at most 4 ulps total; working_prec - 6 correct bits
113 // comfortably suffice for the rounding test.
114 if float_can_round(
115 quotient.x.significand_ref().unwrap(),
116 working_prec - 6,
117 prec,
118 rm,
119 ) {
120 // Round the mantissa to prec, then place the extended exponent, clamping once to the
121 // Float range as the rounding mode dictates.
122 let (rounded, o) = Float::from_float_prec_round(quotient.x, prec, rm);
123 let mut result = ExtendedFloat::from(rounded);
124 result.exp = result.exp.checked_add(quotient.exp).unwrap();
125 return result.into_float_helper(prec, rm, o);
126 }
127 // Increase the precision.
128 working_prec += increment;
129 increment = working_prec >> 1;
130 }
131}
132
133impl Float {
134 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
135 /// rounding the result to the specified precision and with the specified rounding mode. The
136 /// [`Float`] is taken by value and the base by reference. An [`Ordering`] is also returned,
137 /// indicating whether the rounded value is less than, equal to, or greater than the exact
138 /// value. Although `NaN`s are not comparable to any [`Float`], whenever this function returns a
139 /// `NaN` it also returns `Equal`.
140 ///
141 /// This computes $\log_2 x / \log_2 b$, routing the base through
142 /// [`Float::log_base_2_rational_prec_ref`] so that a base near 1 (where $\log_2 b$ is tiny)
143 /// does not lose accuracy to cancellation.
144 ///
145 /// See [`RoundingMode`] for a description of the possible rounding modes.
146 ///
147 /// $$
148 /// f(x,b,p,m) = \log_b x+\varepsilon.
149 /// $$
150 /// - If $\log_b x$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or assumed to be
151 /// 0.
152 /// - If $\log_b x$ is finite and nonzero, and $m$ is not `Nearest`, then $|\varepsilon| <
153 /// 2^{\lfloor\log_2 |\log_b x|\rfloor-p+1}$.
154 /// - If $\log_b x$ is finite and nonzero, and $m$ is `Nearest`, then $|\varepsilon| \leq
155 /// 2^{\lfloor\log_2 |\log_b x|\rfloor-p}$.
156 ///
157 /// If the output has a precision, it is `prec`.
158 ///
159 /// Special cases:
160 /// - $f(\text{NaN},b,p,m)=\text{NaN}$
161 /// - $f(\infty,b,p,m)=\infty$
162 /// - $f(-\infty,b,p,m)=\text{NaN}$
163 /// - $f(\pm0.0,b,p,m)=-\infty$
164 /// - $f(x,b,p,m)=\text{NaN}$ for $x<0$
165 /// - $f(1.0,b,p,m)=0$
166 /// - $f(x,b,p,m)=a/e$ when $x=g^a$, where $g$ is the primitive root of $b$ and $b=g^e$, rounded
167 /// to precision $p$; the result is exact if and only if $a/e$ is representable with precision
168 /// $p$ (for example $\log_4 8=3/2$ is exact)
169 ///
170 /// Unlike a logarithm with an integer base, this function can both overflow (for a base near 1)
171 /// and underflow (for an $x$ near 1).
172 ///
173 /// # Worst-case complexity
174 /// $T(n) = O(n (\log n)^2 \log\log n)$
175 ///
176 /// $M(n) = O(n (\log n)^2)$
177 ///
178 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
179 ///
180 /// # Panics
181 /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
182 /// the result cannot be represented exactly with the given precision.
183 ///
184 /// # Examples
185 /// ```
186 /// use malachite_base::rounding_modes::RoundingMode::*;
187 /// use malachite_float::Float;
188 /// use malachite_q::Rational;
189 /// use std::cmp::Ordering::*;
190 ///
191 /// let (log, o) =
192 /// Float::from(8).log_base_rational_base_prec_round(&Rational::from(4), 10, Exact);
193 /// assert_eq!(log.to_string(), "1.5"); // log_4(8) = 3/2
194 /// assert_eq!(o, Equal);
195 ///
196 /// let (log, o) =
197 /// Float::from(9).log_base_rational_base_prec_round(&Rational::from(3), 10, Exact);
198 /// assert_eq!(log.to_string(), "2.0"); // log_3(9) = 2
199 /// assert_eq!(o, Equal);
200 /// ```
201 #[inline]
202 pub fn log_base_rational_base_prec_round(
203 self,
204 base: &Rational,
205 prec: u64,
206 rm: RoundingMode,
207 ) -> (Self, Ordering) {
208 assert_ne!(prec, 0);
209 assert!(*base > 1u32, "Logarithm base must be greater than 1");
210 match self {
211 Self(NaN | Infinity { sign: false } | Finite { sign: false, .. }) => {
212 (float_nan!(), Equal)
213 }
214 float_either_zero!() => (float_negative_infinity!(), Equal),
215 float_infinity!() => (float_infinity!(), Equal),
216 _ => log_base_rational_base_prec_round_normal(&self, base, prec, rm),
217 }
218 }
219
220 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
221 /// rounding the result to the specified precision and with the specified rounding mode. The
222 /// [`Float`] and the base are both taken by reference. An [`Ordering`] is also returned,
223 /// indicating whether the rounded value is less than, equal to, or greater than the exact
224 /// value.
225 ///
226 /// See [`Float::log_base_rational_base_prec_round`] for details, special cases, and a
227 /// description of the rounding behavior.
228 ///
229 /// # Worst-case complexity
230 /// $T(n) = O(n (\log n)^2 \log\log n)$
231 ///
232 /// $M(n) = O(n (\log n)^2)$
233 ///
234 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
235 ///
236 /// # Panics
237 /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
238 /// the result cannot be represented exactly with the given precision.
239 ///
240 /// # Examples
241 /// ```
242 /// use malachite_base::rounding_modes::RoundingMode::*;
243 /// use malachite_float::Float;
244 /// use malachite_q::Rational;
245 /// use std::cmp::Ordering::*;
246 ///
247 /// let (log, o) =
248 /// (&Float::from(8)).log_base_rational_base_prec_round_ref(&Rational::from(2), 10, Exact);
249 /// assert_eq!(log.to_string(), "3.0"); // log_2(8) = 3
250 /// assert_eq!(o, Equal);
251 ///
252 /// let (log, o) =
253 /// (&Float::from(2)).log_base_rational_base_prec_round_ref(&Rational::from(4), 10, Exact);
254 /// assert_eq!(log.to_string(), "0.5"); // log_4(2) = 1/2
255 /// assert_eq!(o, Equal);
256 /// ```
257 #[inline]
258 pub fn log_base_rational_base_prec_round_ref(
259 &self,
260 base: &Rational,
261 prec: u64,
262 rm: RoundingMode,
263 ) -> (Self, Ordering) {
264 assert_ne!(prec, 0);
265 assert!(*base > 1u32, "Logarithm base must be greater than 1");
266 match self {
267 Self(NaN | Infinity { sign: false } | Finite { sign: false, .. }) => {
268 (float_nan!(), Equal)
269 }
270 float_either_zero!() => (float_negative_infinity!(), Equal),
271 float_infinity!() => (float_infinity!(), Equal),
272 _ => log_base_rational_base_prec_round_normal(self, base, prec, rm),
273 }
274 }
275
276 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
277 /// rounding the result to the nearest value of the specified precision. The [`Float`] is taken
278 /// by value and the base by reference. An [`Ordering`] is also returned.
279 ///
280 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
281 ///
282 /// # Worst-case complexity
283 /// $T(n) = O(n (\log n)^2 \log\log n)$
284 ///
285 /// $M(n) = O(n (\log n)^2)$
286 ///
287 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
288 ///
289 /// # Panics
290 /// Panics if `prec` is zero or if `base` is less than or equal to 1.
291 ///
292 /// # Examples
293 /// ```
294 /// use malachite_float::Float;
295 /// use malachite_q::Rational;
296 /// use std::cmp::Ordering::*;
297 ///
298 /// let (log, o) = Float::from(8).log_base_rational_base_prec(&Rational::from(4), 10);
299 /// assert_eq!(log.to_string(), "1.5"); // log_4(8) = 3/2
300 /// assert_eq!(o, Equal);
301 ///
302 /// let (log, o) = Float::from(9).log_base_rational_base_prec(&Rational::from(3), 10);
303 /// assert_eq!(log.to_string(), "2.0"); // log_3(9) = 2
304 /// assert_eq!(o, Equal);
305 /// ```
306 #[inline]
307 pub fn log_base_rational_base_prec(self, base: &Rational, prec: u64) -> (Self, Ordering) {
308 self.log_base_rational_base_prec_round(base, prec, Nearest)
309 }
310
311 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
312 /// rounding the result to the nearest value of the specified precision. The [`Float`] and the
313 /// base are both taken by reference. An [`Ordering`] is also returned.
314 ///
315 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
316 ///
317 /// # Worst-case complexity
318 /// $T(n) = O(n (\log n)^2 \log\log n)$
319 ///
320 /// $M(n) = O(n (\log n)^2)$
321 ///
322 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
323 ///
324 /// # Panics
325 /// Panics if `prec` is zero or if `base` is less than or equal to 1.
326 ///
327 /// # Examples
328 /// ```
329 /// use malachite_float::Float;
330 /// use malachite_q::Rational;
331 /// use std::cmp::Ordering::*;
332 ///
333 /// let (log, o) = (&Float::from(8)).log_base_rational_base_prec_ref(&Rational::from(2), 10);
334 /// assert_eq!(log.to_string(), "3.0"); // log_2(8) = 3
335 /// assert_eq!(o, Equal);
336 ///
337 /// let (log, o) = (&Float::from(2)).log_base_rational_base_prec_ref(&Rational::from(4), 10);
338 /// assert_eq!(log.to_string(), "0.5"); // log_4(2) = 1/2
339 /// assert_eq!(o, Equal);
340 /// ```
341 #[inline]
342 pub fn log_base_rational_base_prec_ref(&self, base: &Rational, prec: u64) -> (Self, Ordering) {
343 self.log_base_rational_base_prec_round_ref(base, prec, Nearest)
344 }
345
346 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
347 /// rounding the result to the precision of the input and with the specified rounding mode. The
348 /// [`Float`] is taken by value and the base by reference. An [`Ordering`] is also returned.
349 ///
350 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
351 ///
352 /// # Worst-case complexity
353 /// $T(n) = O(n (\log n)^2 \log\log n)$
354 ///
355 /// $M(n) = O(n (\log n)^2)$
356 ///
357 /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
358 ///
359 /// # Panics
360 /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
361 /// represented exactly with the input's precision.
362 ///
363 /// # Examples
364 /// ```
365 /// use malachite_base::rounding_modes::RoundingMode::*;
366 /// use malachite_float::Float;
367 /// use malachite_q::Rational;
368 /// use std::cmp::Ordering::*;
369 ///
370 /// let (log, o) = Float::from(9).log_base_rational_base_round(&Rational::from(3), Exact);
371 /// assert_eq!(log.to_string(), "2.0"); // log_3(9) = 2
372 /// assert_eq!(o, Equal);
373 ///
374 /// let (log, o) = Float::from(2).log_base_rational_base_round(&Rational::from(4), Exact);
375 /// assert_eq!(log.to_string(), "0.5"); // log_4(2) = 1/2
376 /// assert_eq!(o, Equal);
377 /// ```
378 #[inline]
379 pub fn log_base_rational_base_round(
380 self,
381 base: &Rational,
382 rm: RoundingMode,
383 ) -> (Self, Ordering) {
384 let prec = self.significant_bits();
385 self.log_base_rational_base_prec_round(base, prec, rm)
386 }
387
388 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
389 /// rounding the result to the precision of the input and with the specified rounding mode. The
390 /// [`Float`] and the base are both taken by reference. An [`Ordering`] is also returned.
391 ///
392 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
393 ///
394 /// # Worst-case complexity
395 /// $T(n) = O(n (\log n)^2 \log\log n)$
396 ///
397 /// $M(n) = O(n (\log n)^2)$
398 ///
399 /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
400 ///
401 /// # Panics
402 /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
403 /// represented exactly with the input's precision.
404 ///
405 /// # Examples
406 /// ```
407 /// use malachite_base::rounding_modes::RoundingMode::*;
408 /// use malachite_float::Float;
409 /// use malachite_q::Rational;
410 /// use std::cmp::Ordering::*;
411 ///
412 /// let (log, o) =
413 /// (&Float::from(81)).log_base_rational_base_round_ref(&Rational::from(3), Exact);
414 /// assert_eq!(log.to_string(), "4.0"); // log_3(81) = 4
415 /// assert_eq!(o, Equal);
416 ///
417 /// let (log, o) =
418 /// (&Float::from(9)).log_base_rational_base_round_ref(&Rational::from(3), Exact);
419 /// assert_eq!(log.to_string(), "2.0"); // log_3(9) = 2
420 /// assert_eq!(o, Equal);
421 /// ```
422 #[inline]
423 pub fn log_base_rational_base_round_ref(
424 &self,
425 base: &Rational,
426 rm: RoundingMode,
427 ) -> (Self, Ordering) {
428 self.log_base_rational_base_prec_round_ref(base, self.significant_bits(), rm)
429 }
430
431 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1, in
432 /// place, rounding the result to the specified precision and with the specified rounding mode.
433 /// The base is taken by reference. An [`Ordering`] is returned.
434 ///
435 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
436 ///
437 /// # Worst-case complexity
438 /// $T(n) = O(n (\log n)^2 \log\log n)$
439 ///
440 /// $M(n) = O(n (\log n)^2)$
441 ///
442 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
443 ///
444 /// # Panics
445 /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
446 /// the result cannot be represented exactly with the given precision.
447 ///
448 /// # Examples
449 /// ```
450 /// use malachite_base::rounding_modes::RoundingMode::*;
451 /// use malachite_float::Float;
452 /// use malachite_q::Rational;
453 /// use std::cmp::Ordering::*;
454 ///
455 /// let mut x = Float::from(8);
456 /// assert_eq!(
457 /// x.log_base_rational_base_prec_round_assign(&Rational::from(4), 10, Exact),
458 /// Equal
459 /// );
460 /// assert_eq!(x.to_string(), "1.5"); // log_4(8) = 3/2
461 ///
462 /// let mut x = Float::from(9);
463 /// assert_eq!(
464 /// x.log_base_rational_base_prec_round_assign(&Rational::from(3), 10, Exact),
465 /// Equal
466 /// );
467 /// assert_eq!(x.to_string(), "2.0"); // log_3(9) = 2
468 /// ```
469 #[inline]
470 pub fn log_base_rational_base_prec_round_assign(
471 &mut self,
472 base: &Rational,
473 prec: u64,
474 rm: RoundingMode,
475 ) -> Ordering {
476 let (result, o) = core::mem::take(self).log_base_rational_base_prec_round(base, prec, rm);
477 *self = result;
478 o
479 }
480
481 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1, in
482 /// place, rounding the result to the nearest value of the specified precision. The base is
483 /// taken by reference. An [`Ordering`] is returned.
484 ///
485 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
486 ///
487 /// # Worst-case complexity
488 /// $T(n) = O(n (\log n)^2 \log\log n)$
489 ///
490 /// $M(n) = O(n (\log n)^2)$
491 ///
492 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
493 ///
494 /// # Panics
495 /// Panics if `prec` is zero or if `base` is less than or equal to 1.
496 ///
497 /// # Examples
498 /// ```
499 /// use malachite_float::Float;
500 /// use malachite_q::Rational;
501 ///
502 /// let mut x = Float::from(8);
503 /// x.log_base_rational_base_prec_assign(&Rational::from(4), 10);
504 /// assert_eq!(x.to_string(), "1.5"); // log_4(8) = 3/2
505 ///
506 /// let mut x = Float::from(9);
507 /// x.log_base_rational_base_prec_assign(&Rational::from(3), 10);
508 /// assert_eq!(x.to_string(), "2.0"); // log_3(9) = 2
509 /// ```
510 #[inline]
511 pub fn log_base_rational_base_prec_assign(&mut self, base: &Rational, prec: u64) -> Ordering {
512 self.log_base_rational_base_prec_round_assign(base, prec, Nearest)
513 }
514
515 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1, in
516 /// place, rounding the result to the precision of the input and with the specified rounding
517 /// mode. The base is taken by reference. An [`Ordering`] is returned.
518 ///
519 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
520 ///
521 /// # Worst-case complexity
522 /// $T(n) = O(n (\log n)^2 \log\log n)$
523 ///
524 /// $M(n) = O(n (\log n)^2)$
525 ///
526 /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
527 ///
528 /// # Panics
529 /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
530 /// represented exactly with the input's precision.
531 ///
532 /// # Examples
533 /// ```
534 /// use malachite_base::rounding_modes::RoundingMode::*;
535 /// use malachite_float::Float;
536 /// use malachite_q::Rational;
537 ///
538 /// let mut x = Float::from(9);
539 /// x.log_base_rational_base_round_assign(&Rational::from(3), Exact);
540 /// assert_eq!(x.to_string(), "2.0"); // log_3(9) = 2
541 ///
542 /// let mut x = Float::from(2);
543 /// x.log_base_rational_base_round_assign(&Rational::from(4), Exact);
544 /// assert_eq!(x.to_string(), "0.5"); // log_4(2) = 1/2
545 /// ```
546 #[inline]
547 pub fn log_base_rational_base_round_assign(
548 &mut self,
549 base: &Rational,
550 rm: RoundingMode,
551 ) -> Ordering {
552 let prec = self.significant_bits();
553 self.log_base_rational_base_prec_round_assign(base, prec, rm)
554 }
555}
556
557impl LogBase<Rational> for Float {
558 type Output = Self;
559
560 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
561 /// rounding the result to the nearest value of the input's precision. Both are taken by value.
562 ///
563 /// See [`Float::log_base_rational_base_prec_round`] for special cases.
564 ///
565 /// # Worst-case complexity
566 /// $T(n) = O(n (\log n)^2 \log\log n)$
567 ///
568 /// $M(n) = O(n (\log n)^2)$
569 ///
570 /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
571 ///
572 /// # Panics
573 /// Panics if `base` is less than or equal to 1.
574 ///
575 /// # Examples
576 /// ```
577 /// use malachite_base::num::arithmetic::traits::LogBase;
578 /// use malachite_float::Float;
579 /// use malachite_q::Rational;
580 ///
581 /// assert_eq!(
582 /// Float::from(2).log_base(Rational::from(4)).to_string(),
583 /// "0.5"
584 /// ); // log_4(2) = 1/2
585 /// assert_eq!(
586 /// Float::from(9).log_base(Rational::from(3)).to_string(),
587 /// "2.0"
588 /// ); // log_3(9) = 2
589 /// ```
590 #[inline]
591 fn log_base(self, base: Rational) -> Self {
592 let prec = self.significant_bits();
593 self.log_base_rational_base_prec_round(&base, prec, Nearest)
594 .0
595 }
596}
597
598impl LogBase<&Rational> for &Float {
599 type Output = Float;
600
601 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
602 /// rounding the result to the nearest value of the input's precision. Both are taken by
603 /// reference.
604 ///
605 /// See [`Float::log_base_rational_base_prec_round`] for special cases.
606 ///
607 /// # Worst-case complexity
608 /// $T(n) = O(n (\log n)^2 \log\log n)$
609 ///
610 /// $M(n) = O(n (\log n)^2)$
611 ///
612 /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
613 ///
614 /// # Panics
615 /// Panics if `base` is less than or equal to 1.
616 ///
617 /// # Examples
618 /// ```
619 /// use malachite_base::num::arithmetic::traits::LogBase;
620 /// use malachite_float::Float;
621 /// use malachite_q::Rational;
622 ///
623 /// assert_eq!(
624 /// (&Float::from(81)).log_base(&Rational::from(3)).to_string(),
625 /// "4.0"
626 /// ); // log_3(81) = 4
627 /// assert_eq!(
628 /// (&Float::from(9)).log_base(&Rational::from(3)).to_string(),
629 /// "2.0"
630 /// ); // log_3(9) = 2
631 /// ```
632 #[inline]
633 fn log_base(self, base: &Rational) -> Float {
634 self.log_base_rational_base_prec_round_ref(base, self.significant_bits(), Nearest)
635 .0
636 }
637}
638
639impl LogBaseAssign<&Rational> for Float {
640 /// Replaces a [`Float`] $x$ with $\log_b x$, where $b$ is a [`Rational`] greater than 1,
641 /// rounding the result to the nearest value of the input's precision. The base is taken by
642 /// reference.
643 ///
644 /// See [`Float::log_base_rational_base_prec_round`] for special cases.
645 ///
646 /// # Worst-case complexity
647 /// $T(n) = O(n (\log n)^2 \log\log n)$
648 ///
649 /// $M(n) = O(n (\log n)^2)$
650 ///
651 /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
652 ///
653 /// # Panics
654 /// Panics if `base` is less than or equal to 1.
655 ///
656 /// # Examples
657 /// ```
658 /// use malachite_base::num::arithmetic::traits::LogBaseAssign;
659 /// use malachite_float::Float;
660 /// use malachite_q::Rational;
661 ///
662 /// let mut x = Float::from(81);
663 /// x.log_base_assign(&Rational::from(3));
664 /// assert_eq!(x.to_string(), "4.0"); // log_3(81) = 4
665 ///
666 /// let mut x = Float::from(9);
667 /// x.log_base_assign(&Rational::from(3));
668 /// assert_eq!(x.to_string(), "2.0"); // log_3(9) = 2
669 /// ```
670 #[inline]
671 fn log_base_assign(&mut self, base: &Rational) {
672 let prec = self.significant_bits();
673 self.log_base_rational_base_prec_round_assign(base, prec, Nearest);
674 }
675}
676
677/// Computes $\log_b x$, the base-$b$ logarithm of a primitive float, where $b$ is a [`Rational`]
678/// greater than 1. Using this function is more accurate than computing the logarithm using the
679/// standard library, whose logarithm functions are not always correctly rounded.
680///
681/// The base-$b$ logarithm of any negative number is `NaN`.
682///
683/// $$
684/// f(x,b) = \log_b x+\varepsilon.
685/// $$
686/// - If $\log_b x$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or assumed to be 0.
687/// - If $\log_b x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2 |\log_b
688/// x|\rfloor-p}$, where $p$ is precision of the output (typically 24 if `T` is a [`f32`] and 53
689/// if `T` is a [`f64`], but less if the output is subnormal).
690///
691/// Special cases:
692/// - $f(\text{NaN},b)=\text{NaN}$
693/// - $f(\infty,b)=\infty$
694/// - $f(-\infty,b)=\text{NaN}$
695/// - $f(\pm0.0,b)=-\infty$
696/// - $f(1.0,b)=0.0$
697/// - $f(x,b)=\text{NaN}$ for $x<0$
698///
699/// Unlike a logarithm with an integer base, this function can both overflow (for a base near 1) and
700/// underflow (for an $x$ near 1).
701///
702/// # Worst-case complexity
703/// Constant time and additional memory.
704///
705/// # Panics
706/// Panics if `base` is less than or equal to 1.
707///
708/// # Examples
709/// ```
710/// use malachite_base::num::basic::traits::NegativeInfinity;
711/// use malachite_base::num::float::NiceFloat;
712/// use malachite_float::arithmetic::log_base_rational_base::primitive_float_log_base_rational_base;
713/// use malachite_q::Rational;
714///
715/// assert!(primitive_float_log_base_rational_base(f32::NAN, &Rational::from(10)).is_nan());
716/// assert_eq!(
717/// NiceFloat(primitive_float_log_base_rational_base(
718/// 0.0f32,
719/// &Rational::from(10)
720/// )),
721/// NiceFloat(f32::NEGATIVE_INFINITY)
722/// );
723/// // log_4(8) = 3/2
724/// assert_eq!(
725/// NiceFloat(primitive_float_log_base_rational_base(
726/// 8.0f32,
727/// &Rational::from(4)
728/// )),
729/// NiceFloat(1.5)
730/// );
731/// // log_(3/2)(2.25) = 2
732/// assert_eq!(
733/// NiceFloat(primitive_float_log_base_rational_base(
734/// 2.25f32,
735/// &Rational::from_unsigneds(3u8, 2)
736/// )),
737/// NiceFloat(2.0)
738/// );
739/// // log_10(50)
740/// assert_eq!(
741/// NiceFloat(primitive_float_log_base_rational_base(
742/// 50.0f32,
743/// &Rational::from(10)
744/// )),
745/// NiceFloat(1.69897)
746/// );
747/// assert!(primitive_float_log_base_rational_base(-1.0f32, &Rational::from(10)).is_nan());
748/// ```
749#[inline]
750#[allow(clippy::type_repetition_in_bounds)]
751pub fn primitive_float_log_base_rational_base<T: PrimitiveFloat>(x: T, base: &Rational) -> T
752where
753 Float: From<T> + PartialOrd<T>,
754 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
755{
756 emulate_float_to_float_fn(|x, prec| x.log_base_rational_base_prec(base, prec), x)
757}