malachite_float/float/arithmetic/log_base_rational_base.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::{Finite, Infinity, NaN, Zero};
10use crate::float::arithmetic::ln::{SliverOfOne, sliver_of_one};
11use crate::float::arithmetic::log_base::{
12 dyadic_log_of_rational_root, odd_significand_and_exponent,
13};
14use crate::float::arithmetic::log_base_2::extended_log_base_2_of_rational;
15use crate::float::basic::extended::ExtendedFloat;
16use crate::{
17 Float, emulate_float_to_float_fn, float_either_zero, float_infinity, float_nan,
18 float_negative_infinity,
19};
20use core::cmp::Ordering::{self, *};
21use malachite_base::num::arithmetic::traits::{CeilingLogBase2, LogBase, LogBaseAssign};
22use malachite_base::num::basic::floats::PrimitiveFloat;
23use malachite_base::num::basic::integers::PrimitiveInt;
24use malachite_base::num::basic::traits::Zero as ZeroTrait;
25use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
26use malachite_base::num::factorization::traits::ExpressAsPower;
27use malachite_base::num::logic::traits::SignificantBits;
28use malachite_base::rounding_modes::RoundingMode::{self, *};
29use malachite_nz::natural::arithmetic::float::round::float_can_round;
30use malachite_nz::platform::Limb;
31use malachite_q::Rational;
32
33// Returns `Some(log_base(x))` when it is rational, and `None` when it is irrational. The input `x`
34// must be finite, positive, and not equal to 1, and `base` must be greater than 1.
35//
36// `log_base(x)` is rational exactly when `x` and `base` are both powers of a common rational `g`,
37// say `x = g^a` and `base = g^e_base`; then `log_base(x) = a / e_base`. Taking `g` to be the
38// primitive root of `base` (`base.express_as_power()`), this holds iff `x` is an integer power of
39// `g` (including a negative power when `x < 1`), found by `Rational::checked_log_base`.
40//
41// Detecting these rational results up front is essential, not just an optimization: when the result
42// is exactly representable (for example `log_9(3) = 1/2`), the Ziv loop in
43// `log_base_rational_base_prec_round_normal` would never terminate, because its rounding test
44// cannot resolve the ordering (less than, equal to, or greater than the representable value) of a
45// result sitting exactly on a representable point or tie. That holds in every rounding mode, so
46// every exactly-representable result must be caught here.
47//
48// The check is complete and cheap for any input. No size cutoff is sound here: representable
49// results can have enormous exponents with few significant bits (`log_4` of the smallest positive
50// `Float` is `-2^29`, exact at precision 1), and a small `x` can be a root of an enormous `base`
51// (`log_{3^k}(3) = 1/k`, representable whenever `k` is a power of 2). So instead of materializing
52// `x` as a `Rational` under a size bound, the match runs on `x`'s odd significand (at most
53// `prec(x)` bits) and `i64` exponent arithmetic; `express_as_power(base)` costs polynomial in
54// `base`, a value the caller holds materialized anyway.
55pub(crate) fn rational_log_base_rational_base(x: &Float, base: &Rational) -> Option<Rational> {
56 // `express_as_power` returns `None` when `base` is not a perfect power, in which case `base`
57 // itself is `g` (with exponent 1).
58 let (root, e_base) = base.express_as_power().unwrap_or_else(|| (base.clone(), 1));
59 let (s, t) = odd_significand_and_exponent(x);
60 let m = dyadic_log_of_rational_root(&s, t, &root)?;
61 Some(Rational::from_signeds(m, i64::exact_from(e_base)))
62}
63
64// The computation of log_base(x) for a `Rational` base is done by log_base(x) = log_2(x) /
65// log_2(base). The input is finite, nonzero, and positive, and `base` is greater than 1.
66//
67// `log_2(base)` is computed in the extended exponent range (see `extended_log_base_2_of_rational`)
68// so that a base near 1 -- where `log_2(base)` is tiny and would otherwise underflow an ordinary
69// `Float`, losing the operand entirely -- is represented faithfully. The quotient is also kept
70// extended, and the single conversion back to a `Float`, via `ExtendedFloat::into_float_helper`,
71// performs the one correctly-rounded clamp to an infinity/maximum or zero/minimum per the rounding
72// mode. Unlike an integer base, a `Rational` base allows both overflow (base near 1) and underflow
73// (x near 1); both are handled by that clamp. (`log_2(x)` itself never underflows: `x` is a
74// `Float`, so `|x - 1|` is at least the smallest positive `Float`, keeping `|log_2(x)|`
75// representable.)
76fn log_base_rational_base_prec_round_normal(
77 x: &Float,
78 base: &Rational,
79 prec: u64,
80 rm: RoundingMode,
81) -> (Float, Ordering) {
82 // If x is 1, the result is 0.
83 if *x == 1u32 {
84 return (Float::ZERO, Equal);
85 }
86 // If log_base(x) is rational -- x and base are both powers of a common rational -- compute it
87 // directly. This includes exactly-representable results (which the Ziv loop could never
88 // certify) as well as non-representable rationals (cheaper and exact this way).
89 if let Some(q) = rational_log_base_rational_base(x, base) {
90 return Float::from_rational_prec_round(q, prec, rm);
91 }
92 // log_base(x) for x in a sliver of 1 can fall below the smallest positive Float; the 1-plus-x
93 // form handles that underflow region.
94 match sliver_of_one(x) {
95 SliverOfOne::Representable(d) => {
96 return d.log_base_rational_base_1_plus_x_prec_round(base, prec, rm);
97 }
98 SliverOfOne::Underflow => {
99 return Float::log_base_rational_rational_base_prec_round_ref(
100 &Rational::exact_from(x),
101 base,
102 prec,
103 rm,
104 );
105 }
106 SliverOfOne::No => {}
107 }
108 // The result is irrational, so it is never exactly representable.
109 assert_ne!(rm, Exact, "Inexact log_base_rational_base");
110 // The initial slack keeps working_prec at least 7, so the working_prec - 6 below stays
111 // positive.
112 let mut working_prec = prec + 6 + prec.ceiling_log_base_2();
113 let mut increment = Limb::WIDTH;
114 loop {
115 // log_2(x), correctly rounded to working_prec; finite and nonzero (x is positive and not
116 // 1), and never underflowing, so the ordinary log wrapped as an ExtendedFloat suffices.
117 let num = ExtendedFloat::from(x.log_base_2_prec_ref(working_prec).0);
118 // log_2(base) > 0, extended (may be tiny for a base near 1).
119 let den = extended_log_base_2_of_rational(base, working_prec);
120 // log_2(x) / log_2(base) in the extended range; cannot overflow or underflow here.
121 let quotient = num.div_prec_val_ref(&den, working_prec).0;
122 // log_2(x) is correctly rounded (<= 1/2 ulp), log_2(base) is within 2 ulps, and the
123 // division adds at most 1 more, for at most 4 ulps total; working_prec - 6 correct bits
124 // comfortably suffice for the rounding test.
125 if float_can_round(
126 quotient.x.significand_ref().unwrap(),
127 working_prec - 6,
128 prec,
129 rm,
130 ) {
131 // Round the mantissa to prec, then place the extended exponent, clamping once to the
132 // Float range as the rounding mode dictates.
133 let (rounded, o) = Float::from_float_prec_round(quotient.x, prec, rm);
134 let mut result = ExtendedFloat::from(rounded);
135 result.exp = result.exp.checked_add(quotient.exp).unwrap();
136 return result.into_float_helper(prec, rm, o);
137 }
138 // Increase the precision.
139 working_prec += increment;
140 increment = working_prec >> 1;
141 }
142}
143
144impl Float {
145 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
146 /// rounding the result to the specified precision and with the specified rounding mode. The
147 /// [`Float`] is taken by value and the base by reference. An [`Ordering`] is also returned,
148 /// indicating whether the rounded value is less than, equal to, or greater than the exact
149 /// value. Although `NaN`s are not comparable to any [`Float`], whenever this function returns a
150 /// `NaN` it also returns `Equal`.
151 ///
152 /// This computes $\log_2 x / \log_2 b$, routing the base through
153 /// [`Float::log_base_2_rational_prec_ref`] so that a base near 1 (where $\log_2 b$ is tiny)
154 /// does not lose accuracy to cancellation.
155 ///
156 /// See [`RoundingMode`] for a description of the possible rounding modes.
157 ///
158 /// $$
159 /// f(x,b,p,m) = \log_b x+\varepsilon.
160 /// $$
161 /// - If $\log_b x$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or assumed to be
162 /// 0.
163 /// - If $\log_b x$ is finite and nonzero, and $m$ is not `Nearest`, then $|\varepsilon| <
164 /// 2^{\lfloor\log_2 |\log_b x|\rfloor-p+1}$.
165 /// - If $\log_b x$ is finite and nonzero, and $m$ is `Nearest`, then $|\varepsilon| \leq
166 /// 2^{\lfloor\log_2 |\log_b x|\rfloor-p}$.
167 ///
168 /// If the output has a precision, it is `prec`.
169 ///
170 /// Special cases:
171 /// - $f(\text{NaN},b,p,m)=\text{NaN}$
172 /// - $f(\infty,b,p,m)=\infty$
173 /// - $f(-\infty,b,p,m)=\text{NaN}$
174 /// - $f(\pm0.0,b,p,m)=-\infty$
175 /// - $f(x,b,p,m)=\text{NaN}$ for $x<0$
176 /// - $f(1.0,b,p,m)=0$
177 /// - $f(x,b,p,m)=a/e$ when $x=g^a$, where $g$ is the primitive root of $b$ and $b=g^e$, rounded
178 /// to precision $p$; the result is exact if and only if $a/e$ is representable with precision
179 /// $p$ (for example $\log_4 8=3/2$ is exact)
180 ///
181 /// Unlike a logarithm with an integer base, this function can both overflow (for a base near 1)
182 /// and underflow (for an $x$ near 1).
183 ///
184 /// # Worst-case complexity
185 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
186 ///
187 /// $M(n, m) = O(n \log n + m \log m)$
188 ///
189 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
190 /// `max(self.significant_bits(), base.significant_bits())`.
191 ///
192 /// # Panics
193 /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
194 /// the result cannot be represented exactly with the given precision.
195 ///
196 /// # Examples
197 /// ```
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) =
204 /// Float::from(8).log_base_rational_base_prec_round(&Rational::from(4), 10, Exact);
205 /// assert_eq!(log.to_string(), "1.5000"); // log_4(8) = 3/2
206 /// assert_eq!(o, Equal);
207 ///
208 /// let (log, o) =
209 /// Float::from(9).log_base_rational_base_prec_round(&Rational::from(3), 10, Exact);
210 /// assert_eq!(log.to_string(), "2.0000"); // log_3(9) = 2
211 /// assert_eq!(o, Equal);
212 /// ```
213 #[inline]
214 pub fn log_base_rational_base_prec_round(
215 self,
216 base: &Rational,
217 prec: u64,
218 rm: RoundingMode,
219 ) -> (Self, Ordering) {
220 assert_ne!(prec, 0);
221 assert!(*base > 1u32, "Logarithm base must be greater than 1");
222 match self {
223 Self(NaN | Infinity { sign: false } | Finite { sign: false, .. }) => {
224 (float_nan!(), Equal)
225 }
226 float_either_zero!() => (float_negative_infinity!(), Equal),
227 float_infinity!() => (float_infinity!(), Equal),
228 _ => log_base_rational_base_prec_round_normal(&self, base, prec, rm),
229 }
230 }
231
232 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
233 /// rounding the result to the specified precision and with the specified rounding mode. The
234 /// [`Float`] and the base are both taken by reference. An [`Ordering`] is also returned,
235 /// indicating whether the rounded value is less than, equal to, or greater than the exact
236 /// value.
237 ///
238 /// See [`Float::log_base_rational_base_prec_round`] for details, special cases, and a
239 /// description of the rounding behavior.
240 ///
241 /// # Worst-case complexity
242 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
243 ///
244 /// $M(n, m) = O(n \log n + m \log m)$
245 ///
246 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
247 /// `max(self.significant_bits(), base.significant_bits())`.
248 ///
249 /// # Panics
250 /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
251 /// the result cannot be represented exactly with the given precision.
252 ///
253 /// # Examples
254 /// ```
255 /// use malachite_base::num::basic::traits::Two;
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) =
262 /// (&Float::from(8)).log_base_rational_base_prec_round_ref(&Rational::TWO, 10, Exact);
263 /// assert_eq!(log.to_string(), "3.0000"); // log_2(8) = 3
264 /// assert_eq!(o, Equal);
265 ///
266 /// let (log, o) =
267 /// (&Float::TWO).log_base_rational_base_prec_round_ref(&Rational::from(4), 10, Exact);
268 /// assert_eq!(log.to_string(), "0.50000"); // log_4(2) = 1/2
269 /// assert_eq!(o, Equal);
270 /// ```
271 #[inline]
272 pub fn log_base_rational_base_prec_round_ref(
273 &self,
274 base: &Rational,
275 prec: u64,
276 rm: RoundingMode,
277 ) -> (Self, Ordering) {
278 assert_ne!(prec, 0);
279 assert!(*base > 1u32, "Logarithm base must be greater than 1");
280 match self {
281 Self(NaN | Infinity { sign: false } | Finite { sign: false, .. }) => {
282 (float_nan!(), Equal)
283 }
284 float_either_zero!() => (float_negative_infinity!(), Equal),
285 float_infinity!() => (float_infinity!(), Equal),
286 _ => log_base_rational_base_prec_round_normal(self, base, prec, rm),
287 }
288 }
289
290 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
291 /// rounding the result to the nearest value of the specified precision. The [`Float`] is taken
292 /// by value and the base by reference. An [`Ordering`] is also returned.
293 ///
294 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
295 ///
296 /// # Worst-case complexity
297 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
298 ///
299 /// $M(n, m) = O(n \log n + m \log m)$
300 ///
301 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
302 /// `max(self.significant_bits(), base.significant_bits())`.
303 ///
304 /// # Panics
305 /// Panics if `prec` is zero or if `base` is less than or equal to 1.
306 ///
307 /// # Examples
308 /// ```
309 /// use malachite_float::Float;
310 /// use malachite_q::Rational;
311 /// use std::cmp::Ordering::*;
312 ///
313 /// let (log, o) = Float::from(8).log_base_rational_base_prec(&Rational::from(4), 10);
314 /// assert_eq!(log.to_string(), "1.5000"); // log_4(8) = 3/2
315 /// assert_eq!(o, Equal);
316 ///
317 /// let (log, o) = Float::from(9).log_base_rational_base_prec(&Rational::from(3), 10);
318 /// assert_eq!(log.to_string(), "2.0000"); // log_3(9) = 2
319 /// assert_eq!(o, Equal);
320 /// ```
321 #[inline]
322 pub fn log_base_rational_base_prec(self, base: &Rational, prec: u64) -> (Self, Ordering) {
323 self.log_base_rational_base_prec_round(base, prec, Nearest)
324 }
325
326 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
327 /// rounding the result to the nearest value of the specified precision. The [`Float`] and the
328 /// base are both taken by reference. An [`Ordering`] is also returned.
329 ///
330 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
331 ///
332 /// # Worst-case complexity
333 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
334 ///
335 /// $M(n, m) = O(n \log n + m \log m)$
336 ///
337 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
338 /// `max(self.significant_bits(), base.significant_bits())`.
339 ///
340 /// # Panics
341 /// Panics if `prec` is zero or if `base` is less than or equal to 1.
342 ///
343 /// # Examples
344 /// ```
345 /// use malachite_base::num::basic::traits::Two;
346 /// use malachite_float::Float;
347 /// use malachite_q::Rational;
348 /// use std::cmp::Ordering::*;
349 ///
350 /// let (log, o) = (&Float::from(8)).log_base_rational_base_prec_ref(&Rational::TWO, 10);
351 /// assert_eq!(log.to_string(), "3.0000"); // log_2(8) = 3
352 /// assert_eq!(o, Equal);
353 ///
354 /// let (log, o) = (&Float::TWO).log_base_rational_base_prec_ref(&Rational::from(4), 10);
355 /// assert_eq!(log.to_string(), "0.50000"); // log_4(2) = 1/2
356 /// assert_eq!(o, Equal);
357 /// ```
358 #[inline]
359 pub fn log_base_rational_base_prec_ref(&self, base: &Rational, prec: u64) -> (Self, Ordering) {
360 self.log_base_rational_base_prec_round_ref(base, prec, Nearest)
361 }
362
363 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
364 /// rounding the result to the precision of the input and with the specified rounding mode. The
365 /// [`Float`] is taken by value and the base by reference. An [`Ordering`] is also returned.
366 ///
367 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
368 ///
369 /// # Worst-case complexity
370 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
371 ///
372 /// $M(n, m) = O(n \log n + m \log m)$
373 ///
374 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
375 /// `base.significant_bits()`.
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::num::basic::traits::Two;
384 /// use malachite_base::rounding_modes::RoundingMode::*;
385 /// use malachite_float::Float;
386 /// use malachite_q::Rational;
387 /// use std::cmp::Ordering::*;
388 ///
389 /// let (log, o) = Float::from(9).log_base_rational_base_round(&Rational::from(3), Exact);
390 /// assert_eq!(log.to_string(), "2.00"); // log_3(9) = 2
391 /// assert_eq!(o, Equal);
392 ///
393 /// let (log, o) = Float::TWO.log_base_rational_base_round(&Rational::from(4), Exact);
394 /// assert_eq!(log.to_string(), "0.50"); // log_4(2) = 1/2
395 /// assert_eq!(o, Equal);
396 /// ```
397 #[inline]
398 pub fn log_base_rational_base_round(
399 self,
400 base: &Rational,
401 rm: RoundingMode,
402 ) -> (Self, Ordering) {
403 let prec = self.significant_bits();
404 self.log_base_rational_base_prec_round(base, prec, rm)
405 }
406
407 /// Computes $\log_b 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_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(81)).log_base_rational_base_round_ref(&Rational::from(3), Exact);
434 /// assert_eq!(log.to_string(), "4.000"); // log_3(81) = 4
435 /// assert_eq!(o, Equal);
436 ///
437 /// let (log, o) =
438 /// (&Float::from(9)).log_base_rational_base_round_ref(&Rational::from(3), Exact);
439 /// assert_eq!(log.to_string(), "2.00"); // log_3(9) = 2
440 /// assert_eq!(o, Equal);
441 /// ```
442 #[inline]
443 pub fn log_base_rational_base_round_ref(
444 &self,
445 base: &Rational,
446 rm: RoundingMode,
447 ) -> (Self, Ordering) {
448 self.log_base_rational_base_prec_round_ref(base, self.significant_bits(), rm)
449 }
450
451 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1, in
452 /// place, rounding the result to the specified precision and with the specified rounding mode.
453 /// The base is taken by reference. An [`Ordering`] is returned.
454 ///
455 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
456 ///
457 /// # Worst-case complexity
458 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
459 ///
460 /// $M(n, m) = O(n \log n + m \log m)$
461 ///
462 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
463 /// `max(self.significant_bits(), base.significant_bits())`.
464 ///
465 /// # Panics
466 /// Panics if `prec` is zero, if `base` is less than or equal to 1, or if `rm` is `Exact` but
467 /// the result cannot be represented exactly with the given precision.
468 ///
469 /// # Examples
470 /// ```
471 /// use malachite_base::rounding_modes::RoundingMode::*;
472 /// use malachite_float::Float;
473 /// use malachite_q::Rational;
474 /// use std::cmp::Ordering::*;
475 ///
476 /// let mut x = Float::from(8);
477 /// assert_eq!(
478 /// x.log_base_rational_base_prec_round_assign(&Rational::from(4), 10, Exact),
479 /// Equal
480 /// );
481 /// assert_eq!(x.to_string(), "1.5000"); // log_4(8) = 3/2
482 ///
483 /// let mut x = Float::from(9);
484 /// assert_eq!(
485 /// x.log_base_rational_base_prec_round_assign(&Rational::from(3), 10, Exact),
486 /// Equal
487 /// );
488 /// assert_eq!(x.to_string(), "2.0000"); // log_3(9) = 2
489 /// ```
490 #[inline]
491 pub fn log_base_rational_base_prec_round_assign(
492 &mut self,
493 base: &Rational,
494 prec: u64,
495 rm: RoundingMode,
496 ) -> Ordering {
497 let (result, o) = core::mem::take(self).log_base_rational_base_prec_round(base, prec, rm);
498 *self = result;
499 o
500 }
501
502 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1, in
503 /// place, rounding the result to the nearest value of the specified precision. The base is
504 /// taken by reference. An [`Ordering`] is returned.
505 ///
506 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
507 ///
508 /// # Worst-case complexity
509 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
510 ///
511 /// $M(n, m) = O(n \log n + m \log m)$
512 ///
513 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
514 /// `max(self.significant_bits(), base.significant_bits())`.
515 ///
516 /// # Panics
517 /// Panics if `prec` is zero or if `base` is less than or equal to 1.
518 ///
519 /// # Examples
520 /// ```
521 /// use malachite_float::Float;
522 /// use malachite_q::Rational;
523 ///
524 /// let mut x = Float::from(8);
525 /// x.log_base_rational_base_prec_assign(&Rational::from(4), 10);
526 /// assert_eq!(x.to_string(), "1.5000"); // log_4(8) = 3/2
527 ///
528 /// let mut x = Float::from(9);
529 /// x.log_base_rational_base_prec_assign(&Rational::from(3), 10);
530 /// assert_eq!(x.to_string(), "2.0000"); // log_3(9) = 2
531 /// ```
532 #[inline]
533 pub fn log_base_rational_base_prec_assign(&mut self, base: &Rational, prec: u64) -> Ordering {
534 self.log_base_rational_base_prec_round_assign(base, prec, Nearest)
535 }
536
537 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1, in
538 /// place, rounding the result to the precision of the input and with the specified rounding
539 /// mode. The base is taken by reference. An [`Ordering`] is returned.
540 ///
541 /// See [`Float::log_base_rational_base_prec_round`] for details and special cases.
542 ///
543 /// # Worst-case complexity
544 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
545 ///
546 /// $M(n, m) = O(n \log n + m \log m)$
547 ///
548 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
549 /// `base.significant_bits()`.
550 ///
551 /// # Panics
552 /// Panics if `base` is less than or equal to 1, or if `rm` is `Exact` but the result cannot be
553 /// represented exactly with the input's precision.
554 ///
555 /// # Examples
556 /// ```
557 /// use malachite_base::num::basic::traits::Two;
558 /// use malachite_base::rounding_modes::RoundingMode::*;
559 /// use malachite_float::Float;
560 /// use malachite_q::Rational;
561 ///
562 /// let mut x = Float::from(9);
563 /// x.log_base_rational_base_round_assign(&Rational::from(3), Exact);
564 /// assert_eq!(x.to_string(), "2.00"); // log_3(9) = 2
565 ///
566 /// let mut x = Float::TWO;
567 /// x.log_base_rational_base_round_assign(&Rational::from(4), Exact);
568 /// assert_eq!(x.to_string(), "0.50"); // log_4(2) = 1/2
569 /// ```
570 #[inline]
571 pub fn log_base_rational_base_round_assign(
572 &mut self,
573 base: &Rational,
574 rm: RoundingMode,
575 ) -> Ordering {
576 let prec = self.significant_bits();
577 self.log_base_rational_base_prec_round_assign(base, prec, rm)
578 }
579}
580
581impl LogBase<Rational> for Float {
582 type Output = Self;
583
584 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
585 /// rounding the result to the nearest value of the input's precision. Both are taken by value.
586 ///
587 /// See [`Float::log_base_rational_base_prec_round`] for special cases.
588 ///
589 /// # Worst-case complexity
590 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
591 ///
592 /// $M(n, m) = O(n \log n + m \log m)$
593 ///
594 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
595 /// `base.significant_bits()`.
596 ///
597 /// # Panics
598 /// Panics if `base` is less than or equal to 1.
599 ///
600 /// # Examples
601 /// ```
602 /// use malachite_base::num::arithmetic::traits::LogBase;
603 /// use malachite_base::num::basic::traits::Two;
604 /// use malachite_float::Float;
605 /// use malachite_q::Rational;
606 ///
607 /// assert_eq!(Float::TWO.log_base(Rational::from(4)).to_string(), "0.50"); // log_4(2) = 1/2
608 /// assert_eq!(
609 /// Float::from(9).log_base(Rational::from(3)).to_string(),
610 /// "2.00"
611 /// ); // log_3(9) = 2
612 /// ```
613 #[inline]
614 fn log_base(self, base: Rational) -> Self {
615 let prec = self.significant_bits();
616 self.log_base_rational_base_prec_round(&base, prec, Nearest)
617 .0
618 }
619}
620
621impl LogBase<&Rational> for &Float {
622 type Output = Float;
623
624 /// Computes $\log_b x$, where $x$ is a [`Float`] and $b$ is a [`Rational`] greater than 1,
625 /// rounding the result to the nearest value of the input's precision. Both are taken by
626 /// reference.
627 ///
628 /// See [`Float::log_base_rational_base_prec_round`] for special cases.
629 ///
630 /// # Worst-case complexity
631 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
632 ///
633 /// $M(n, m) = O(n \log n + m \log m)$
634 ///
635 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
636 /// `base.significant_bits()`.
637 ///
638 /// # Panics
639 /// Panics if `base` is less than or equal to 1.
640 ///
641 /// # Examples
642 /// ```
643 /// use malachite_base::num::arithmetic::traits::LogBase;
644 /// use malachite_float::Float;
645 /// use malachite_q::Rational;
646 ///
647 /// assert_eq!(
648 /// (&Float::from(81)).log_base(&Rational::from(3)).to_string(),
649 /// "4.000"
650 /// ); // log_3(81) = 4
651 /// assert_eq!(
652 /// (&Float::from(9)).log_base(&Rational::from(3)).to_string(),
653 /// "2.00"
654 /// ); // log_3(9) = 2
655 /// ```
656 #[inline]
657 fn log_base(self, base: &Rational) -> Float {
658 self.log_base_rational_base_prec_round_ref(base, self.significant_bits(), Nearest)
659 .0
660 }
661}
662
663impl LogBaseAssign<&Rational> for Float {
664 /// Replaces a [`Float`] $x$ with $\log_b x$, where $b$ is a [`Rational`] greater than 1,
665 /// rounding the result to the nearest value of the input's precision. The base is taken by
666 /// reference.
667 ///
668 /// See [`Float::log_base_rational_base_prec_round`] for special cases.
669 ///
670 /// # Worst-case complexity
671 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
672 ///
673 /// $M(n, m) = O(n \log n + m \log m)$
674 ///
675 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
676 /// `base.significant_bits()`.
677 ///
678 /// # Panics
679 /// Panics if `base` is less than or equal to 1.
680 ///
681 /// # Examples
682 /// ```
683 /// use malachite_base::num::arithmetic::traits::LogBaseAssign;
684 /// use malachite_float::Float;
685 /// use malachite_q::Rational;
686 ///
687 /// let mut x = Float::from(81);
688 /// x.log_base_assign(&Rational::from(3));
689 /// assert_eq!(x.to_string(), "4.000"); // log_3(81) = 4
690 ///
691 /// let mut x = Float::from(9);
692 /// x.log_base_assign(&Rational::from(3));
693 /// assert_eq!(x.to_string(), "2.00"); // log_3(9) = 2
694 /// ```
695 #[inline]
696 fn log_base_assign(&mut self, base: &Rational) {
697 let prec = self.significant_bits();
698 self.log_base_rational_base_prec_round_assign(base, prec, Nearest);
699 }
700}
701
702/// Computes $\log_b x$, the base-$b$ logarithm of a primitive float, where $b$ is a [`Rational`]
703/// greater than 1. Using this function is more accurate than computing the logarithm using the
704/// standard library, whose logarithm functions are not always correctly rounded.
705///
706/// The base-$b$ logarithm of any negative number is `NaN`.
707///
708/// $$
709/// f(x,b) = \log_b x+\varepsilon.
710/// $$
711/// - If $\log_b x$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or assumed to be 0.
712/// - If $\log_b x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2 |\log_b
713/// x|\rfloor-p}$, where $p$ is precision of the output (typically 24 if `T` is a [`f32`] and 53
714/// if `T` is a [`f64`], but less if the output is subnormal).
715///
716/// Special cases:
717/// - $f(\text{NaN},b)=\text{NaN}$
718/// - $f(\infty,b)=\infty$
719/// - $f(-\infty,b)=\text{NaN}$
720/// - $f(\pm0.0,b)=-\infty$
721/// - $f(1.0,b)=0.0$
722/// - $f(x,b)=\text{NaN}$ for $x<0$
723///
724/// Unlike a logarithm with an integer base, this function can both overflow (for a base near 1) and
725/// underflow (for an $x$ near 1).
726///
727/// # Worst-case complexity
728/// $T(m) = O(m \log m \log\log m)$
729///
730/// $M(m) = O(m \log m)$
731///
732/// where $T$ is time, $M$ is additional memory, and $m$ is `base.significant_bits()`.
733///
734/// # Panics
735/// Panics if `base` is less than or equal to 1.
736///
737/// # Examples
738/// ```
739/// use malachite_base::num::basic::traits::NegativeInfinity;
740/// use malachite_base::num::float::NiceFloat;
741/// use malachite_float::float::arithmetic::log_base_rational_base::*;
742/// use malachite_q::Rational;
743///
744/// assert!(primitive_float_log_base_rational_base(f32::NAN, &Rational::from(10)).is_nan());
745/// assert_eq!(
746/// NiceFloat(primitive_float_log_base_rational_base(
747/// 0.0f32,
748/// &Rational::from(10)
749/// )),
750/// NiceFloat(f32::NEGATIVE_INFINITY)
751/// );
752/// // log_4(8) = 3/2
753/// assert_eq!(
754/// NiceFloat(primitive_float_log_base_rational_base(
755/// 8.0f32,
756/// &Rational::from(4)
757/// )),
758/// NiceFloat(1.5)
759/// );
760/// // log_(3/2)(2.25) = 2
761/// assert_eq!(
762/// NiceFloat(primitive_float_log_base_rational_base(
763/// 2.25f32,
764/// &Rational::from_unsigneds(3u8, 2)
765/// )),
766/// NiceFloat(2.0)
767/// );
768/// // log_10(50)
769/// assert_eq!(
770/// NiceFloat(primitive_float_log_base_rational_base(
771/// 50.0f32,
772/// &Rational::from(10)
773/// )),
774/// NiceFloat(1.69897)
775/// );
776/// assert!(primitive_float_log_base_rational_base(-1.0f32, &Rational::from(10)).is_nan());
777/// ```
778#[inline]
779#[allow(clippy::type_repetition_in_bounds)]
780pub fn primitive_float_log_base_rational_base<T: PrimitiveFloat>(x: T, base: &Rational) -> T
781where
782 Float: From<T> + PartialOrd<T>,
783 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
784{
785 emulate_float_to_float_fn(|x, prec| x.log_base_rational_base_prec(base, prec), x)
786}