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::round::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, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
185 ///
186 /// $M(n, m) = O(n \log n + m \log m)$
187 ///
188 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
189 /// `max(self.significant_bits(), base.significant_bits())`.
190 ///
191 /// # Panics
192 /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
193 /// the result cannot be represented exactly with the given precision.
194 ///
195 /// # Examples
196 /// ```
197 /// use malachite_base::num::basic::traits::One;
198 /// use malachite_base::rounding_modes::RoundingMode::*;
199 /// use malachite_float::Float;
200 /// use malachite_q::Rational;
201 /// use std::cmp::Ordering::*;
202 ///
203 /// let (log, o) = Float::from(3).log_base_rational_base_1_plus_x_prec_round(
204 /// &Rational::from(4),
205 /// 10,
206 /// Exact,
207 /// );
208 /// assert_eq!(log.to_string(), "1.0000"); // log_4(1 + 3) = log_4(4) = 1
209 /// assert_eq!(o, Equal);
210 ///
211 /// let (log, o) =
212 /// Float::ONE.log_base_rational_base_1_plus_x_prec_round(&Rational::from(4), 10, Exact);
213 /// assert_eq!(log.to_string(), "0.50000"); // log_4(1 + 1) = log_4(2) = 1/2
214 /// assert_eq!(o, Equal);
215 /// ```
216 #[inline]
217 pub fn log_base_rational_base_1_plus_x_prec_round(
218 self,
219 base: &Rational,
220 prec: u64,
221 rm: RoundingMode,
222 ) -> (Self, Ordering) {
223 assert_ne!(prec, 0);
224 assert!(*base > 1u32, "Logarithm base must be greater than 1");
225 match self {
226 Self(NaN | Infinity { sign: false }) => (float_nan!(), Equal),
227 float_infinity!() => (float_infinity!(), Equal),
228 Self(Zero { .. }) => (self, Equal),
229 _ => log_base_rational_base_1_plus_x_prec_round_normal(&self, base, prec, rm),
230 }
231 }
232
233 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
234 /// rounding the result to the specified precision and with the specified rounding mode. The
235 /// [`Float`] and the base are both taken by reference. An [`Ordering`] is also returned,
236 /// indicating whether the rounded value is less than, equal to, or greater than the exact
237 /// value.
238 ///
239 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for details, special cases, and a
240 /// description of the rounding behavior.
241 ///
242 /// # Worst-case complexity
243 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
244 ///
245 /// $M(n, m) = O(n \log n + m \log m)$
246 ///
247 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
248 /// `max(self.significant_bits(), base.significant_bits())`.
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::num::basic::traits::One;
257 /// use malachite_base::rounding_modes::RoundingMode::*;
258 /// use malachite_float::Float;
259 /// use malachite_q::Rational;
260 /// use std::cmp::Ordering::*;
261 ///
262 /// let (log, o) = (&Float::from(8)).log_base_rational_base_1_plus_x_prec_round_ref(
263 /// &Rational::from(3),
264 /// 10,
265 /// Exact,
266 /// );
267 /// assert_eq!(log.to_string(), "2.0000"); // log_3(1 + 8) = log_3(9) = 2
268 /// assert_eq!(o, Equal);
269 ///
270 /// let (log, o) = (&Float::ONE).log_base_rational_base_1_plus_x_prec_round_ref(
271 /// &Rational::from(3),
272 /// 20,
273 /// Floor,
274 /// );
275 /// assert_eq!(log.to_string(), "0.63092899"); // log_3(2), rounded down
276 /// assert_eq!(o, Less);
277 /// ```
278 pub fn log_base_rational_base_1_plus_x_prec_round_ref(
279 &self,
280 base: &Rational,
281 prec: u64,
282 rm: RoundingMode,
283 ) -> (Self, Ordering) {
284 assert_ne!(prec, 0);
285 assert!(*base > 1u32, "Logarithm base must be greater than 1");
286 match self {
287 Self(NaN | Infinity { sign: false }) => (float_nan!(), Equal),
288 float_infinity!() => (float_infinity!(), Equal),
289 Self(Zero { .. }) => (self.clone(), Equal),
290 _ => log_base_rational_base_1_plus_x_prec_round_normal(self, base, prec, rm),
291 }
292 }
293
294 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
295 /// rounding the result to the nearest value of the specified precision. The [`Float`] is taken
296 /// by value and the base by reference. An [`Ordering`] is also returned.
297 ///
298 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for details and special cases.
299 ///
300 /// # Worst-case complexity
301 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
302 ///
303 /// $M(n, m) = O(n \log n + m \log m)$
304 ///
305 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
306 /// `max(self.significant_bits(), base.significant_bits())`.
307 ///
308 /// # Panics
309 /// Panics if `prec` is zero or if `base` is less than or equal to 1.
310 ///
311 /// # Examples
312 /// ```
313 /// use malachite_float::Float;
314 /// use malachite_q::Rational;
315 /// use std::cmp::Ordering::*;
316 ///
317 /// let (log, o) = Float::from(8).log_base_rational_base_1_plus_x_prec(&Rational::from(3), 10);
318 /// assert_eq!(log.to_string(), "2.0000"); // log_3(1 + 8) = log_3(9) = 2
319 /// assert_eq!(o, Equal);
320 /// ```
321 #[inline]
322 pub fn log_base_rational_base_1_plus_x_prec(
323 self,
324 base: &Rational,
325 prec: u64,
326 ) -> (Self, Ordering) {
327 self.log_base_rational_base_1_plus_x_prec_round(base, prec, Nearest)
328 }
329
330 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
331 /// rounding the result to the nearest value of the specified precision. The [`Float`] and the
332 /// base are both taken by reference. An [`Ordering`] is also returned.
333 ///
334 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for details and special cases.
335 ///
336 /// # Worst-case complexity
337 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
338 ///
339 /// $M(n, m) = O(n \log n + m \log m)$
340 ///
341 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
342 /// `max(self.significant_bits(), base.significant_bits())`.
343 ///
344 /// # Panics
345 /// Panics if `prec` is zero or if `base` is less than or equal to 1.
346 ///
347 /// # Examples
348 /// ```
349 /// use malachite_float::Float;
350 /// use malachite_q::Rational;
351 /// use std::cmp::Ordering::*;
352 ///
353 /// let (log, o) =
354 /// (&Float::from(8)).log_base_rational_base_1_plus_x_prec_ref(&Rational::from(3), 10);
355 /// assert_eq!(log.to_string(), "2.0000"); // log_3(1 + 8) = log_3(9) = 2
356 /// assert_eq!(o, Equal);
357 /// ```
358 #[inline]
359 pub fn log_base_rational_base_1_plus_x_prec_ref(
360 &self,
361 base: &Rational,
362 prec: u64,
363 ) -> (Self, Ordering) {
364 self.log_base_rational_base_1_plus_x_prec_round_ref(base, prec, Nearest)
365 }
366
367 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
368 /// rounding the result to the precision of the input and with the specified rounding mode. The
369 /// [`Float`] is taken by value and the base by reference. An [`Ordering`] is also returned.
370 ///
371 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for details and special cases.
372 ///
373 /// # Worst-case complexity
374 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
375 ///
376 /// $M(n, m) = O(n \log n + m \log m)$
377 ///
378 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
379 /// `base.significant_bits()`.
380 ///
381 /// # Panics
382 /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
383 /// represented exactly with the input's precision.
384 ///
385 /// # Examples
386 /// ```
387 /// use malachite_base::rounding_modes::RoundingMode::*;
388 /// use malachite_float::Float;
389 /// use malachite_q::Rational;
390 /// use std::cmp::Ordering::*;
391 ///
392 /// let (log, o) =
393 /// Float::from(8).log_base_rational_base_1_plus_x_round(&Rational::from(3), Exact);
394 /// assert_eq!(log.to_string(), "2.0"); // log_3(1 + 8) = log_3(9) = 2
395 /// assert_eq!(o, Equal);
396 /// ```
397 #[inline]
398 pub fn log_base_rational_base_1_plus_x_round(
399 self,
400 base: &Rational,
401 rm: RoundingMode,
402 ) -> (Self, Ordering) {
403 let prec = self.significant_bits();
404 self.log_base_rational_base_1_plus_x_prec_round(base, prec, rm)
405 }
406
407 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
408 /// rounding the result to the precision of the input and with the specified rounding mode. The
409 /// [`Float`] and the base are both taken by reference. An [`Ordering`] is also returned.
410 ///
411 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for details and special cases.
412 ///
413 /// # Worst-case complexity
414 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
415 ///
416 /// $M(n, m) = O(n \log n + m \log m)$
417 ///
418 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
419 /// `base.significant_bits()`.
420 ///
421 /// # Panics
422 /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
423 /// represented exactly with the input's precision.
424 ///
425 /// # Examples
426 /// ```
427 /// use malachite_base::rounding_modes::RoundingMode::*;
428 /// use malachite_float::Float;
429 /// use malachite_q::Rational;
430 /// use std::cmp::Ordering::*;
431 ///
432 /// let (log, o) =
433 /// (&Float::from(8)).log_base_rational_base_1_plus_x_round_ref(&Rational::from(3), Exact);
434 /// assert_eq!(log.to_string(), "2.0"); // log_3(1 + 8) = log_3(9) = 2
435 /// assert_eq!(o, Equal);
436 /// ```
437 #[inline]
438 pub fn log_base_rational_base_1_plus_x_round_ref(
439 &self,
440 base: &Rational,
441 rm: RoundingMode,
442 ) -> (Self, Ordering) {
443 self.log_base_rational_base_1_plus_x_prec_round_ref(base, self.significant_bits(), rm)
444 }
445
446 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
447 /// in place, rounding the result to the specified precision and with the specified rounding
448 /// mode. The base is taken by reference. An [`Ordering`] is returned.
449 ///
450 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for details and special cases.
451 ///
452 /// # Worst-case complexity
453 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
454 ///
455 /// $M(n, m) = O(n \log n + m \log m)$
456 ///
457 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
458 /// `max(self.significant_bits(), base.significant_bits())`.
459 ///
460 /// # Panics
461 /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
462 /// the result cannot be represented exactly with the given precision.
463 ///
464 /// # Examples
465 /// ```
466 /// use malachite_base::rounding_modes::RoundingMode::*;
467 /// use malachite_float::Float;
468 /// use malachite_q::Rational;
469 /// use std::cmp::Ordering::*;
470 ///
471 /// let mut x = Float::from(8);
472 /// assert_eq!(
473 /// x.log_base_rational_base_1_plus_x_prec_round_assign(&Rational::from(3), 10, Exact),
474 /// Equal
475 /// );
476 /// assert_eq!(x.to_string(), "2.0000"); // log_3(1 + 8) = log_3(9) = 2
477 /// ```
478 #[inline]
479 pub fn log_base_rational_base_1_plus_x_prec_round_assign(
480 &mut self,
481 base: &Rational,
482 prec: u64,
483 rm: RoundingMode,
484 ) -> Ordering {
485 let (result, o) =
486 core::mem::take(self).log_base_rational_base_1_plus_x_prec_round(base, prec, rm);
487 *self = result;
488 o
489 }
490
491 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
492 /// in place, rounding the result to the nearest value of the specified precision. The base is
493 /// taken by reference. An [`Ordering`] is returned.
494 ///
495 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for details and special cases.
496 ///
497 /// # Worst-case complexity
498 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
499 ///
500 /// $M(n, m) = O(n \log n + m \log m)$
501 ///
502 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
503 /// `max(self.significant_bits(), base.significant_bits())`.
504 ///
505 /// # Panics
506 /// Panics if `prec` is zero or if `base` is less than or equal to 1.
507 ///
508 /// # Examples
509 /// ```
510 /// use malachite_float::Float;
511 /// use malachite_q::Rational;
512 ///
513 /// let mut x = Float::from(8);
514 /// x.log_base_rational_base_1_plus_x_prec_assign(&Rational::from(3), 10);
515 /// assert_eq!(x.to_string(), "2.0000"); // log_3(1 + 8) = log_3(9) = 2
516 /// ```
517 #[inline]
518 pub fn log_base_rational_base_1_plus_x_prec_assign(
519 &mut self,
520 base: &Rational,
521 prec: u64,
522 ) -> Ordering {
523 self.log_base_rational_base_1_plus_x_prec_round_assign(base, prec, Nearest)
524 }
525
526 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
527 /// in place, rounding the result to the precision of the input and with the specified rounding
528 /// mode. The base is taken by reference. An [`Ordering`] is returned.
529 ///
530 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for details and special cases.
531 ///
532 /// # Worst-case complexity
533 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
534 ///
535 /// $M(n, m) = O(n \log n + m \log m)$
536 ///
537 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
538 /// `base.significant_bits()`.
539 ///
540 /// # Panics
541 /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
542 /// represented exactly with the input's precision.
543 ///
544 /// # Examples
545 /// ```
546 /// use malachite_base::rounding_modes::RoundingMode::*;
547 /// use malachite_float::Float;
548 /// use malachite_q::Rational;
549 ///
550 /// let mut x = Float::from(8);
551 /// x.log_base_rational_base_1_plus_x_round_assign(&Rational::from(3), Exact);
552 /// assert_eq!(x.to_string(), "2.0"); // log_3(1 + 8) = log_3(9) = 2
553 /// ```
554 #[inline]
555 pub fn log_base_rational_base_1_plus_x_round_assign(
556 &mut self,
557 base: &Rational,
558 rm: RoundingMode,
559 ) -> Ordering {
560 let prec = self.significant_bits();
561 self.log_base_rational_base_1_plus_x_prec_round_assign(base, prec, rm)
562 }
563}
564
565impl LogBaseOf1PlusX<Rational> for Float {
566 type Output = Self;
567
568 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
569 /// rounding the result to the nearest value of the input's precision. Both are taken by value.
570 ///
571 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for special cases.
572 ///
573 /// # Worst-case complexity
574 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
575 ///
576 /// $M(n, m) = O(n \log n + m \log m)$
577 ///
578 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
579 /// `base.significant_bits()`.
580 ///
581 /// # Panics
582 /// Panics if `base` is less than or equal to 1.
583 ///
584 /// # Examples
585 /// ```
586 /// use malachite_base::num::arithmetic::traits::LogBaseOf1PlusX;
587 /// use malachite_float::Float;
588 /// use malachite_q::Rational;
589 ///
590 /// // log_3(1 + 8) = log_3(9) = 2
591 /// assert_eq!(
592 /// Float::from(8)
593 /// .log_base_1_plus_x(Rational::from(3))
594 /// .to_string(),
595 /// "2.0"
596 /// );
597 /// ```
598 #[inline]
599 fn log_base_1_plus_x(self, base: Rational) -> Self {
600 let prec = self.significant_bits();
601 self.log_base_rational_base_1_plus_x_prec_round(&base, prec, Nearest)
602 .0
603 }
604}
605
606impl LogBaseOf1PlusX<&Rational> for &Float {
607 type Output = Float;
608
609 /// Computes $\log_b(1+x)$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
610 /// rounding the result to the nearest value of the input's precision. Both are taken by
611 /// reference.
612 ///
613 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for special cases.
614 ///
615 /// # Worst-case complexity
616 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
617 ///
618 /// $M(n, m) = O(n \log n + m \log m)$
619 ///
620 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
621 /// `base.significant_bits()`.
622 ///
623 /// # Panics
624 /// Panics if `base` is less than or equal to 1.
625 ///
626 /// # Examples
627 /// ```
628 /// use malachite_base::num::arithmetic::traits::LogBaseOf1PlusX;
629 /// use malachite_float::Float;
630 /// use malachite_q::Rational;
631 ///
632 /// // log_3(1 + 8) = log_3(9) = 2
633 /// assert_eq!(
634 /// (&Float::from(8))
635 /// .log_base_1_plus_x(&Rational::from(3))
636 /// .to_string(),
637 /// "2.0"
638 /// );
639 /// ```
640 #[inline]
641 fn log_base_1_plus_x(self, base: &Rational) -> Float {
642 self.log_base_rational_base_1_plus_x_prec_round_ref(base, self.significant_bits(), Nearest)
643 .0
644 }
645}
646
647impl LogBaseOf1PlusXAssign<&Rational> for Float {
648 /// Replaces a [`Float`] $x$ with $\log_b(1+x)$, where $b$ is a [`Rational`] greater than 1,
649 /// rounding the result to the nearest value of the input's precision. The base is taken by
650 /// reference.
651 ///
652 /// See [`Float::log_base_rational_base_1_plus_x_prec_round`] for special cases.
653 ///
654 /// # Worst-case complexity
655 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
656 ///
657 /// $M(n, m) = O(n \log n + m \log m)$
658 ///
659 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
660 /// `base.significant_bits()`.
661 ///
662 /// # Panics
663 /// Panics if `base` is less than or equal to 1.
664 ///
665 /// # Examples
666 /// ```
667 /// use malachite_base::num::arithmetic::traits::LogBaseOf1PlusXAssign;
668 /// use malachite_float::Float;
669 /// use malachite_q::Rational;
670 ///
671 /// let mut x = Float::from(8);
672 /// x.log_base_1_plus_x_assign(&Rational::from(3));
673 /// assert_eq!(x.to_string(), "2.0"); // log_3(1 + 8) = log_3(9) = 2
674 /// ```
675 #[inline]
676 fn log_base_1_plus_x_assign(&mut self, base: &Rational) {
677 let prec = self.significant_bits();
678 self.log_base_rational_base_1_plus_x_prec_round_assign(base, prec, Nearest);
679 }
680}
681
682/// Computes $\log_b(1+x)$, the base-$b$ logarithm of one plus a primitive float, where the base $b$
683/// is a [`Rational`] greater than 1, returning a primitive float result. Using this function is
684/// more accurate than computing the logarithm using the standard library, both because $1+x$ may
685/// not be representable as a primitive float and because the standard library's `log` is not always
686/// correctly rounded.
687///
688/// $\log_b(1+x)$ is undefined for $x<-1$, so whenever $x<-1$, `NaN` is returned.
689///
690/// $$
691/// f(x,b) = \log_b(1+x)+\varepsilon.
692/// $$
693/// - If $\log_b(1+x)$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or assumed to be 0.
694/// - If $\log_b(1+x)$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2
695/// |\log_b(1+x)|\rfloor-p}$, where $p$ is precision of the output (typically 24 if `T` is a
696/// [`f32`] and 53 if `T` is a [`f64`], but less if the output is subnormal).
697///
698/// Special cases:
699/// - $f(\text{NaN},b)=\text{NaN}$
700/// - $f(\infty,b)=\infty$
701/// - $f(-\infty,b)=\text{NaN}$
702/// - $f(\pm0.0,b)=\pm0.0$
703/// - $f(-1.0,b)=-\infty$
704/// - $f(x,b)=\text{NaN}$ for $x<-1$
705///
706/// Unlike a logarithm with an integer base, this function can both overflow (for a base near 1) and
707/// underflow (for an $x$ near 0).
708///
709/// # Worst-case complexity
710/// $T(m) = O(m \log m \log\log m)$
711///
712/// $M(m) = O(m \log m)$
713///
714/// where $T$ is time, $M$ is additional memory, and $m$ is `base.significant_bits()`.
715///
716/// # Panics
717/// Panics if `base` is less than or equal to 1.
718///
719/// # Examples
720/// ```
721/// use malachite_base::num::basic::traits::NegativeInfinity;
722/// use malachite_base::num::float::NiceFloat;
723/// use malachite_float::float::arithmetic::log_base_rational_base_1_plus_x::*;
724/// use malachite_q::Rational;
725///
726/// assert!(
727/// primitive_float_log_base_rational_base_1_plus_x(f32::NAN, &Rational::from(10)).is_nan()
728/// );
729/// assert_eq!(
730/// NiceFloat(primitive_float_log_base_rational_base_1_plus_x(
731/// f32::INFINITY,
732/// &Rational::from(10)
733/// )),
734/// NiceFloat(f32::INFINITY)
735/// );
736/// assert_eq!(
737/// NiceFloat(primitive_float_log_base_rational_base_1_plus_x(
738/// -1.0f32,
739/// &Rational::from(10)
740/// )),
741/// NiceFloat(f32::NEGATIVE_INFINITY)
742/// );
743/// assert!(primitive_float_log_base_rational_base_1_plus_x(-2.0f32, &Rational::from(10)).is_nan());
744/// // log_4(1 + 3) = log_4(4) = 1
745/// assert_eq!(
746/// NiceFloat(primitive_float_log_base_rational_base_1_plus_x(
747/// 3.0f32,
748/// &Rational::from(4)
749/// )),
750/// NiceFloat(1.0)
751/// );
752/// // log_4(1 + 1) = log_4(2) = 1/2
753/// assert_eq!(
754/// NiceFloat(primitive_float_log_base_rational_base_1_plus_x(
755/// 1.0f32,
756/// &Rational::from(4)
757/// )),
758/// NiceFloat(0.5)
759/// );
760/// // log_(3/2)(1 + 1/2) = log_(3/2)(3/2) = 1
761/// assert_eq!(
762/// NiceFloat(primitive_float_log_base_rational_base_1_plus_x(
763/// 0.5f32,
764/// &Rational::from_unsigneds(3u8, 2)
765/// )),
766/// NiceFloat(1.0)
767/// );
768/// ```
769#[inline]
770#[allow(clippy::type_repetition_in_bounds)]
771pub fn primitive_float_log_base_rational_base_1_plus_x<T: PrimitiveFloat>(
772 x: T,
773 base: &Rational,
774) -> T
775where
776 Float: From<T> + PartialOrd<T>,
777 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
778{
779 emulate_float_to_float_fn(
780 |x, prec| x.log_base_rational_base_1_plus_x_prec(base, prec),
781 x,
782 )
783}