Skip to main content

malachite_float/arithmetic/
log_base_rational_base.rs

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