Skip to main content

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