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}