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}