Skip to main content

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