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