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