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_extras::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(
100                Rational::exact_from(x),
101                base.clone(),
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) = O(n (\log n)^2 \log\log n)$
186    ///
187    /// $M(n) = O(n (\log n)^2)$
188    ///
189    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
190    ///
191    /// # Panics
192    /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
193    /// the result cannot be represented exactly with the given precision.
194    ///
195    /// # Examples
196    /// ```
197    /// use malachite_base::rounding_modes::RoundingMode::*;
198    /// use malachite_float::Float;
199    /// use malachite_q::Rational;
200    /// use std::cmp::Ordering::*;
201    ///
202    /// let (log, o) =
203    ///     Float::from(8).log_base_rational_base_prec_round(&Rational::from(4), 10, Exact);
204    /// assert_eq!(log.to_string(), "1.5000"); // log_4(8) = 3/2
205    /// assert_eq!(o, Equal);
206    ///
207    /// let (log, o) =
208    ///     Float::from(9).log_base_rational_base_prec_round(&Rational::from(3), 10, Exact);
209    /// assert_eq!(log.to_string(), "2.0000"); // log_3(9) = 2
210    /// assert_eq!(o, Equal);
211    /// ```
212    #[inline]
213    pub fn log_base_rational_base_prec_round(
214        self,
215        base: &Rational,
216        prec: u64,
217        rm: RoundingMode,
218    ) -> (Self, Ordering) {
219        assert_ne!(prec, 0);
220        assert!(*base > 1u32, "Logarithm base must be greater than 1");
221        match self {
222            Self(NaN | Infinity { sign: false } | Finite { sign: false, .. }) => {
223                (float_nan!(), Equal)
224            }
225            float_either_zero!() => (float_negative_infinity!(), Equal),
226            float_infinity!() => (float_infinity!(), Equal),
227            _ => log_base_rational_base_prec_round_normal(&self, base, prec, rm),
228        }
229    }
230
231    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
232    /// rounding the result to the specified precision and with the specified rounding mode. The
233    /// [`Float`] and the base are both taken by reference. An [`Ordering`] is also returned,
234    /// indicating whether the rounded value is less than, equal to, or greater than the exact
235    /// value.
236    ///
237    /// See [`Float::log_base_rational_base_prec_round`] for details, special cases, and a
238    /// description of the rounding behavior.
239    ///
240    /// # Worst-case complexity
241    /// $T(n) = O(n (\log n)^2 \log\log n)$
242    ///
243    /// $M(n) = O(n (\log n)^2)$
244    ///
245    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
246    ///
247    /// # Panics
248    /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
249    /// the result cannot be represented exactly with the given precision.
250    ///
251    /// # Examples
252    /// ```
253    /// use malachite_base::rounding_modes::RoundingMode::*;
254    /// use malachite_float::Float;
255    /// use malachite_q::Rational;
256    /// use std::cmp::Ordering::*;
257    ///
258    /// let (log, o) =
259    ///     (&Float::from(8)).log_base_rational_base_prec_round_ref(&Rational::from(2), 10, Exact);
260    /// assert_eq!(log.to_string(), "3.0000"); // log_2(8) = 3
261    /// assert_eq!(o, Equal);
262    ///
263    /// let (log, o) =
264    ///     (&Float::from(2)).log_base_rational_base_prec_round_ref(&Rational::from(4), 10, Exact);
265    /// assert_eq!(log.to_string(), "0.50000"); // log_4(2) = 1/2
266    /// assert_eq!(o, Equal);
267    /// ```
268    #[inline]
269    pub fn log_base_rational_base_prec_round_ref(
270        &self,
271        base: &Rational,
272        prec: u64,
273        rm: RoundingMode,
274    ) -> (Self, Ordering) {
275        assert_ne!(prec, 0);
276        assert!(*base > 1u32, "Logarithm base must be greater than 1");
277        match self {
278            Self(NaN | Infinity { sign: false } | Finite { sign: false, .. }) => {
279                (float_nan!(), Equal)
280            }
281            float_either_zero!() => (float_negative_infinity!(), Equal),
282            float_infinity!() => (float_infinity!(), Equal),
283            _ => log_base_rational_base_prec_round_normal(self, base, prec, rm),
284        }
285    }
286
287    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
288    /// rounding the result to the nearest value of the specified precision. The [`Float`] is taken
289    /// by value and the base by reference. An [`Ordering`] is also returned.
290    ///
291    /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
292    ///
293    /// # Worst-case complexity
294    /// $T(n) = O(n (\log n)^2 \log\log n)$
295    ///
296    /// $M(n) = O(n (\log n)^2)$
297    ///
298    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
299    ///
300    /// # Panics
301    /// Panics if `prec` is zero or if `base` is less than or equal to 1.
302    ///
303    /// # Examples
304    /// ```
305    /// use malachite_float::Float;
306    /// use malachite_q::Rational;
307    /// use std::cmp::Ordering::*;
308    ///
309    /// let (log, o) = Float::from(8).log_base_rational_base_prec(&Rational::from(4), 10);
310    /// assert_eq!(log.to_string(), "1.5000"); // log_4(8) = 3/2
311    /// assert_eq!(o, Equal);
312    ///
313    /// let (log, o) = Float::from(9).log_base_rational_base_prec(&Rational::from(3), 10);
314    /// assert_eq!(log.to_string(), "2.0000"); // log_3(9) = 2
315    /// assert_eq!(o, Equal);
316    /// ```
317    #[inline]
318    pub fn log_base_rational_base_prec(self, base: &Rational, prec: u64) -> (Self, Ordering) {
319        self.log_base_rational_base_prec_round(base, prec, Nearest)
320    }
321
322    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
323    /// rounding the result to the nearest value of the specified precision. The [`Float`] and the
324    /// base are both taken by reference. An [`Ordering`] is also returned.
325    ///
326    /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
327    ///
328    /// # Worst-case complexity
329    /// $T(n) = O(n (\log n)^2 \log\log n)$
330    ///
331    /// $M(n) = O(n (\log n)^2)$
332    ///
333    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
334    ///
335    /// # Panics
336    /// Panics if `prec` is zero or if `base` is less than or equal to 1.
337    ///
338    /// # Examples
339    /// ```
340    /// use malachite_float::Float;
341    /// use malachite_q::Rational;
342    /// use std::cmp::Ordering::*;
343    ///
344    /// let (log, o) = (&Float::from(8)).log_base_rational_base_prec_ref(&Rational::from(2), 10);
345    /// assert_eq!(log.to_string(), "3.0000"); // log_2(8) = 3
346    /// assert_eq!(o, Equal);
347    ///
348    /// let (log, o) = (&Float::from(2)).log_base_rational_base_prec_ref(&Rational::from(4), 10);
349    /// assert_eq!(log.to_string(), "0.50000"); // log_4(2) = 1/2
350    /// assert_eq!(o, Equal);
351    /// ```
352    #[inline]
353    pub fn log_base_rational_base_prec_ref(&self, base: &Rational, prec: u64) -> (Self, Ordering) {
354        self.log_base_rational_base_prec_round_ref(base, prec, Nearest)
355    }
356
357    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
358    /// rounding the result to the precision of the input and with the specified rounding mode. The
359    /// [`Float`] is taken by value and the base by reference. An [`Ordering`] is also returned.
360    ///
361    /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
362    ///
363    /// # Worst-case complexity
364    /// $T(n) = O(n (\log n)^2 \log\log n)$
365    ///
366    /// $M(n) = O(n (\log n)^2)$
367    ///
368    /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
369    ///
370    /// # Panics
371    /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
372    /// represented exactly with the input's precision.
373    ///
374    /// # Examples
375    /// ```
376    /// use malachite_base::rounding_modes::RoundingMode::*;
377    /// use malachite_float::Float;
378    /// use malachite_q::Rational;
379    /// use std::cmp::Ordering::*;
380    ///
381    /// let (log, o) = Float::from(9).log_base_rational_base_round(&Rational::from(3), Exact);
382    /// assert_eq!(log.to_string(), "2.00"); // log_3(9) = 2
383    /// assert_eq!(o, Equal);
384    ///
385    /// let (log, o) = Float::from(2).log_base_rational_base_round(&Rational::from(4), Exact);
386    /// assert_eq!(log.to_string(), "0.50"); // log_4(2) = 1/2
387    /// assert_eq!(o, Equal);
388    /// ```
389    #[inline]
390    pub fn log_base_rational_base_round(
391        self,
392        base: &Rational,
393        rm: RoundingMode,
394    ) -> (Self, Ordering) {
395        let prec = self.significant_bits();
396        self.log_base_rational_base_prec_round(base, prec, rm)
397    }
398
399    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
400    /// rounding the result to the precision of the input and with the specified rounding mode. The
401    /// [`Float`] and the base are both taken by reference. An [`Ordering`] is also returned.
402    ///
403    /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
404    ///
405    /// # Worst-case complexity
406    /// $T(n) = O(n (\log n)^2 \log\log n)$
407    ///
408    /// $M(n) = O(n (\log n)^2)$
409    ///
410    /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
411    ///
412    /// # Panics
413    /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
414    /// represented exactly with the input's precision.
415    ///
416    /// # Examples
417    /// ```
418    /// use malachite_base::rounding_modes::RoundingMode::*;
419    /// use malachite_float::Float;
420    /// use malachite_q::Rational;
421    /// use std::cmp::Ordering::*;
422    ///
423    /// let (log, o) =
424    ///     (&Float::from(81)).log_base_rational_base_round_ref(&Rational::from(3), Exact);
425    /// assert_eq!(log.to_string(), "4.000"); // log_3(81) = 4
426    /// assert_eq!(o, Equal);
427    ///
428    /// let (log, o) =
429    ///     (&Float::from(9)).log_base_rational_base_round_ref(&Rational::from(3), Exact);
430    /// assert_eq!(log.to_string(), "2.00"); // log_3(9) = 2
431    /// assert_eq!(o, Equal);
432    /// ```
433    #[inline]
434    pub fn log_base_rational_base_round_ref(
435        &self,
436        base: &Rational,
437        rm: RoundingMode,
438    ) -> (Self, Ordering) {
439        self.log_base_rational_base_prec_round_ref(base, self.significant_bits(), rm)
440    }
441
442    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1, in
443    /// place, rounding the result to the specified precision and with the specified rounding mode.
444    /// The base is taken by reference. An [`Ordering`] is returned.
445    ///
446    /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
447    ///
448    /// # Worst-case complexity
449    /// $T(n) = O(n (\log n)^2 \log\log n)$
450    ///
451    /// $M(n) = O(n (\log n)^2)$
452    ///
453    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
454    ///
455    /// # Panics
456    /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
457    /// the result cannot be represented exactly with the given precision.
458    ///
459    /// # Examples
460    /// ```
461    /// use malachite_base::rounding_modes::RoundingMode::*;
462    /// use malachite_float::Float;
463    /// use malachite_q::Rational;
464    /// use std::cmp::Ordering::*;
465    ///
466    /// let mut x = Float::from(8);
467    /// assert_eq!(
468    ///     x.log_base_rational_base_prec_round_assign(&Rational::from(4), 10, Exact),
469    ///     Equal
470    /// );
471    /// assert_eq!(x.to_string(), "1.5000"); // log_4(8) = 3/2
472    ///
473    /// let mut x = Float::from(9);
474    /// assert_eq!(
475    ///     x.log_base_rational_base_prec_round_assign(&Rational::from(3), 10, Exact),
476    ///     Equal
477    /// );
478    /// assert_eq!(x.to_string(), "2.0000"); // log_3(9) = 2
479    /// ```
480    #[inline]
481    pub fn log_base_rational_base_prec_round_assign(
482        &mut self,
483        base: &Rational,
484        prec: u64,
485        rm: RoundingMode,
486    ) -> Ordering {
487        let (result, o) = core::mem::take(self).log_base_rational_base_prec_round(base, prec, rm);
488        *self = result;
489        o
490    }
491
492    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1, in
493    /// place, rounding the result to the nearest value of the specified precision. The base is
494    /// taken by reference. An [`Ordering`] is returned.
495    ///
496    /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
497    ///
498    /// # Worst-case complexity
499    /// $T(n) = O(n (\log n)^2 \log\log n)$
500    ///
501    /// $M(n) = O(n (\log n)^2)$
502    ///
503    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
504    ///
505    /// # Panics
506    /// Panics if `prec` is zero or if `base` is less than or equal to 1.
507    ///
508    /// # Examples
509    /// ```
510    /// use malachite_float::Float;
511    /// use malachite_q::Rational;
512    ///
513    /// let mut x = Float::from(8);
514    /// x.log_base_rational_base_prec_assign(&Rational::from(4), 10);
515    /// assert_eq!(x.to_string(), "1.5000"); // log_4(8) = 3/2
516    ///
517    /// let mut x = Float::from(9);
518    /// x.log_base_rational_base_prec_assign(&Rational::from(3), 10);
519    /// assert_eq!(x.to_string(), "2.0000"); // log_3(9) = 2
520    /// ```
521    #[inline]
522    pub fn log_base_rational_base_prec_assign(&mut self, base: &Rational, prec: u64) -> Ordering {
523        self.log_base_rational_base_prec_round_assign(base, prec, Nearest)
524    }
525
526    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1, in
527    /// place, rounding the result to the precision of the input and with the specified rounding
528    /// mode. The base is taken by reference. An [`Ordering`] is returned.
529    ///
530    /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
531    ///
532    /// # Worst-case complexity
533    /// $T(n) = O(n (\log n)^2 \log\log n)$
534    ///
535    /// $M(n) = O(n (\log n)^2)$
536    ///
537    /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
538    ///
539    /// # Panics
540    /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
541    /// represented exactly with the input's precision.
542    ///
543    /// # Examples
544    /// ```
545    /// use malachite_base::rounding_modes::RoundingMode::*;
546    /// use malachite_float::Float;
547    /// use malachite_q::Rational;
548    ///
549    /// let mut x = Float::from(9);
550    /// x.log_base_rational_base_round_assign(&Rational::from(3), Exact);
551    /// assert_eq!(x.to_string(), "2.00"); // log_3(9) = 2
552    ///
553    /// let mut x = Float::from(2);
554    /// x.log_base_rational_base_round_assign(&Rational::from(4), Exact);
555    /// assert_eq!(x.to_string(), "0.50"); // log_4(2) = 1/2
556    /// ```
557    #[inline]
558    pub fn log_base_rational_base_round_assign(
559        &mut self,
560        base: &Rational,
561        rm: RoundingMode,
562    ) -> Ordering {
563        let prec = self.significant_bits();
564        self.log_base_rational_base_prec_round_assign(base, prec, rm)
565    }
566}
567
568impl LogBase<Rational> for Float {
569    type Output = Self;
570
571    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
572    /// rounding the result to the nearest value of the input's precision. Both are taken by value.
573    ///
574    /// See [`Float::log_base_rational_base_prec_round`] for special cases.
575    ///
576    /// # Worst-case complexity
577    /// $T(n) = O(n (\log n)^2 \log\log n)$
578    ///
579    /// $M(n) = O(n (\log n)^2)$
580    ///
581    /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
582    ///
583    /// # Panics
584    /// Panics if `base` is less than or equal to 1.
585    ///
586    /// # Examples
587    /// ```
588    /// use malachite_base::num::arithmetic::traits::LogBase;
589    /// use malachite_float::Float;
590    /// use malachite_q::Rational;
591    ///
592    /// assert_eq!(
593    ///     Float::from(2).log_base(Rational::from(4)).to_string(),
594    ///     "0.50"
595    /// ); // log_4(2) = 1/2
596    /// assert_eq!(
597    ///     Float::from(9).log_base(Rational::from(3)).to_string(),
598    ///     "2.00"
599    /// ); // log_3(9) = 2
600    /// ```
601    #[inline]
602    fn log_base(self, base: Rational) -> Self {
603        let prec = self.significant_bits();
604        self.log_base_rational_base_prec_round(&base, prec, Nearest)
605            .0
606    }
607}
608
609impl LogBase<&Rational> for &Float {
610    type Output = Float;
611
612    /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
613    /// rounding the result to the nearest value of the input's precision. Both are taken by
614    /// reference.
615    ///
616    /// See [`Float::log_base_rational_base_prec_round`] for special cases.
617    ///
618    /// # Worst-case complexity
619    /// $T(n) = O(n (\log n)^2 \log\log n)$
620    ///
621    /// $M(n) = O(n (\log n)^2)$
622    ///
623    /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
624    ///
625    /// # Panics
626    /// Panics if `base` is less than or equal to 1.
627    ///
628    /// # Examples
629    /// ```
630    /// use malachite_base::num::arithmetic::traits::LogBase;
631    /// use malachite_float::Float;
632    /// use malachite_q::Rational;
633    ///
634    /// assert_eq!(
635    ///     (&Float::from(81)).log_base(&Rational::from(3)).to_string(),
636    ///     "4.000"
637    /// ); // log_3(81) = 4
638    /// assert_eq!(
639    ///     (&Float::from(9)).log_base(&Rational::from(3)).to_string(),
640    ///     "2.00"
641    /// ); // log_3(9) = 2
642    /// ```
643    #[inline]
644    fn log_base(self, base: &Rational) -> Float {
645        self.log_base_rational_base_prec_round_ref(base, self.significant_bits(), Nearest)
646            .0
647    }
648}
649
650impl LogBaseAssign<&Rational> for Float {
651    /// Replaces a [`Float`] $x$ with $\log_b x$, where $b$ is a [`Rational`] greater than 1,
652    /// rounding the result to the nearest value of the input's precision. The base is taken by
653    /// reference.
654    ///
655    /// See [`Float::log_base_rational_base_prec_round`] for special cases.
656    ///
657    /// # Worst-case complexity
658    /// $T(n) = O(n (\log n)^2 \log\log n)$
659    ///
660    /// $M(n) = O(n (\log n)^2)$
661    ///
662    /// where $T$ is time, $M$ is additional memory, and $n$ is the precision of the input.
663    ///
664    /// # Panics
665    /// Panics if `base` is less than or equal to 1.
666    ///
667    /// # Examples
668    /// ```
669    /// use malachite_base::num::arithmetic::traits::LogBaseAssign;
670    /// use malachite_float::Float;
671    /// use malachite_q::Rational;
672    ///
673    /// let mut x = Float::from(81);
674    /// x.log_base_assign(&Rational::from(3));
675    /// assert_eq!(x.to_string(), "4.000"); // log_3(81) = 4
676    ///
677    /// let mut x = Float::from(9);
678    /// x.log_base_assign(&Rational::from(3));
679    /// assert_eq!(x.to_string(), "2.00"); // log_3(9) = 2
680    /// ```
681    #[inline]
682    fn log_base_assign(&mut self, base: &Rational) {
683        let prec = self.significant_bits();
684        self.log_base_rational_base_prec_round_assign(base, prec, Nearest);
685    }
686}
687
688/// Computes $\log_b x$, the base-$b$ logarithm of a primitive float, where $b$ is a [`Rational`]
689/// greater than 1. Using this function is more accurate than computing the logarithm using the
690/// standard library, whose logarithm functions are not always correctly rounded.
691///
692/// The base-$b$ logarithm of any negative number is `NaN`.
693///
694/// $$
695/// f(x,b) = \log_b x+\varepsilon.
696/// $$
697/// - If $\log_b x$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or assumed to be 0.
698/// - If $\log_b x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2 |\log_b
699///   x|\rfloor-p}$, where $p$ is precision of the output (typically 24 if `T` is a [`f32`] and 53
700///   if `T` is a [`f64`], but less if the output is subnormal).
701///
702/// Special cases:
703/// - $f(\text{NaN},b)=\text{NaN}$
704/// - $f(\infty,b)=\infty$
705/// - $f(-\infty,b)=\text{NaN}$
706/// - $f(\pm0.0,b)=-\infty$
707/// - $f(1.0,b)=0.0$
708/// - $f(x,b)=\text{NaN}$ for $x<0$
709///
710/// Unlike a logarithm with an integer base, this function can both overflow (for a base near 1) and
711/// underflow (for an $x$ near 1).
712///
713/// # Worst-case complexity
714/// Constant time and additional memory.
715///
716/// # Panics
717/// Panics if `base` is less than or equal to 1.
718///
719/// # Examples
720/// ```
721/// use malachite_base::num::basic::traits::NegativeInfinity;
722/// use malachite_base::num::float::NiceFloat;
723/// use malachite_float::float::arithmetic::log_base_rational_base::*;
724/// use malachite_q::Rational;
725///
726/// assert!(primitive_float_log_base_rational_base(f32::NAN, &Rational::from(10)).is_nan());
727/// assert_eq!(
728///     NiceFloat(primitive_float_log_base_rational_base(
729///         0.0f32,
730///         &Rational::from(10)
731///     )),
732///     NiceFloat(f32::NEGATIVE_INFINITY)
733/// );
734/// // log_4(8) = 3/2
735/// assert_eq!(
736///     NiceFloat(primitive_float_log_base_rational_base(
737///         8.0f32,
738///         &Rational::from(4)
739///     )),
740///     NiceFloat(1.5)
741/// );
742/// // log_(3/2)(2.25) = 2
743/// assert_eq!(
744///     NiceFloat(primitive_float_log_base_rational_base(
745///         2.25f32,
746///         &Rational::from_unsigneds(3u8, 2)
747///     )),
748///     NiceFloat(2.0)
749/// );
750/// // log_10(50)
751/// assert_eq!(
752///     NiceFloat(primitive_float_log_base_rational_base(
753///         50.0f32,
754///         &Rational::from(10)
755///     )),
756///     NiceFloat(1.69897)
757/// );
758/// assert!(primitive_float_log_base_rational_base(-1.0f32, &Rational::from(10)).is_nan());
759/// ```
760#[inline]
761#[allow(clippy::type_repetition_in_bounds)]
762pub fn primitive_float_log_base_rational_base<T: PrimitiveFloat>(x: T, base: &Rational) -> T
763where
764    Float: From<T> + PartialOrd<T>,
765    for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
766{
767    emulate_float_to_float_fn(|x, prec| x.log_base_rational_base_prec(base, prec), x)
768}