Skip to main content

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