Skip to main content

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