Skip to main content

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