Skip to main content

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