malachite_float/float/arithmetic/log_base_float_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::{Infinity, NaN};
10use crate::float::arithmetic::ln::{SliverOfOne, sliver_of_one};
11use crate::float::arithmetic::log_base::{
12 dyadic_log_of_root, dyadic_primitive_root, odd_significand_and_exponent,
13};
14use crate::float::basic::extended::ExtendedFloat;
15use crate::{
16 Float, emulate_float_float_to_float_fn, float_infinity, float_nan, float_negative_infinity,
17};
18use core::cmp::Ordering::{self, *};
19use malachite_base::num::arithmetic::traits::{CeilingLogBase2, LogBase, LogBaseAssign};
20use malachite_base::num::basic::floats::PrimitiveFloat;
21use malachite_base::num::basic::integers::PrimitiveInt;
22use malachite_base::num::basic::traits::{NegativeZero, Zero as ZeroTrait};
23use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
24use malachite_base::num::logic::traits::SignificantBits;
25use malachite_base::rounding_modes::RoundingMode::{self, *};
26use malachite_nz::natural::arithmetic::float::round::float_can_round;
27use malachite_nz::platform::Limb;
28use malachite_q::Rational;
29
30// Returns `Some(log_base(x))` when it is rational, and `None` when it is irrational. The inputs `x`
31// and `base` must both be finite, positive, and not equal to 1.
32//
33// `log_base(x)` is rational exactly when `x` and `base` are commensurable (both powers of a common
34// rational). Both are dyadic, so this reuses `rational_log_base_rational_rational_base` on their
35// exact `Rational` values; for a base in (0, 1) -- where `Rational::checked_log_base` requires a
36// base above 1 -- the identity `log_b(x) = -log_{1/b}(x)` reduces to a base above 1.
37//
38// Detecting these rational results up front is essential: the Ziv loop could never certify an
39// exactly-representable one. The check is balloon-safe: it materializes `x` and `base` as
40// `Rational`s only when their exponents and precisions are within `64 * prec`.
41pub(crate) fn log_base_float_base_rational(x: &Float, base: &Float) -> Option<Rational> {
42 // Both x and the base are dyadic: the base's primitive root comes from its odd significand and
43 // exponent, and x is matched against it on its own odd significand and exponent, so neither is
44 // ever materialized as a `Rational` (their exponents may be extreme, making the integer forms
45 // enormous even though the Floats are small). No size cutoff: skipping the check when the
46 // result is exactly representable (such as `log_4` of the smallest positive Float, `-2^29`)
47 // would leave the Ziv loop unable to terminate.
48 let (s_b, t_b) = odd_significand_and_exponent(base);
49 let (z, h, e_base) = dyadic_primitive_root(&s_b, t_b);
50 let (s, t) = odd_significand_and_exponent(x);
51 let m = dyadic_log_of_root(&s, t, z, &h)?;
52 Some(Rational::from_signeds(m, i64::exact_from(e_base)))
53}
54
55// The computation of log_base(x) for a `Float` base is done by log_base(x) = log_2(x) /
56// log_2(base). The inputs are finite, positive, and not equal to 1.
57//
58// Both logarithms are ordinary, correctly-rounded `Float`s (a `Float` operand cannot be close
59// enough to 1 to make its `log_2` underflow at any practical precision), but their quotient can
60// overflow (base near 1, so `log_2(base)` is tiny) or underflow (x near 1). So the operands are
61// wrapped as `ExtendedFloat`s, divided in the extended exponent range, and converted back with a
62// single `into_float_helper` clamp. A base in (0, 1) gives a negative `log_2(base)`, so the
63// division yields the (sign-flipped) result for free.
64fn log_base_float_base_normal(
65 x: &Float,
66 base: &Float,
67 prec: u64,
68 rm: RoundingMode,
69) -> (Float, Ordering) {
70 // log_base(1) = 0, with the sign of 1 / log_2(base): positive for base > 1, negative for a base
71 // in (0, 1).
72 if *x == 1u32 {
73 return if *base < 1u32 {
74 (Float::NEGATIVE_ZERO, Equal)
75 } else {
76 (Float::ZERO, Equal)
77 };
78 }
79 // If log_base(x) is rational -- x and base commensurable -- compute it directly. This includes
80 // exactly-representable results (which the Ziv loop could never certify) as well as
81 // non-representable rationals (cheaper and exact this way).
82 if let Some(q) = log_base_float_base_rational(x, base) {
83 return Float::from_rational_prec_round(q, prec, rm);
84 }
85 // log_base(x) for x in a sliver of 1 can fall below the smallest positive Float; the 1-plus-x
86 // form handles that underflow region.
87 match sliver_of_one(x) {
88 SliverOfOne::Representable(d) => {
89 return d.log_base_float_base_1_plus_x_prec_round(base, prec, rm);
90 }
91 SliverOfOne::Underflow => {
92 return Float::log_base_rational_float_base_prec_round_ref(
93 &Rational::exact_from(x),
94 base,
95 prec,
96 rm,
97 );
98 }
99 SliverOfOne::No => {}
100 }
101 // The result is irrational, so it is never exactly representable.
102 assert_ne!(rm, Exact, "Inexact log_base_float_base");
103 // The initial slack keeps working_prec at least 7, so the working_prec - 6 below stays
104 // positive.
105 let mut working_prec = prec + 6 + prec.ceiling_log_base_2();
106 let mut increment = Limb::WIDTH;
107 loop {
108 // log_2(x) and log_2(base), correctly rounded; both finite and nonzero (x, base positive
109 // and not 1), neither underflowing, so the ordinary logs wrapped as ExtendedFloats suffice.
110 let num = ExtendedFloat::from(x.log_base_2_prec_ref(working_prec).0);
111 let den = ExtendedFloat::from(base.log_base_2_prec_ref(working_prec).0);
112 // log_2(x) / log_2(base) in the extended range; cannot overflow or underflow here.
113 let quotient = num.div_prec_val_ref(&den, working_prec).0;
114 // Two correctly-rounded logs (<= 1/2 ulp each) and the division (<= 1/2 ulp) give under 2
115 // ulps total; working_prec - 6 correct bits comfortably suffice for the rounding test.
116 if float_can_round(
117 quotient.x.significand_ref().unwrap(),
118 working_prec - 6,
119 prec,
120 rm,
121 ) {
122 // Round the mantissa to prec, then place the extended exponent, clamping once to the
123 // Float range as the rounding mode dictates.
124 let (rounded, o) = Float::from_float_prec_round(quotient.x, prec, rm);
125 let mut result = ExtendedFloat::from(rounded);
126 result.exp = result.exp.checked_add(quotient.exp).unwrap();
127 return result.into_float_helper(prec, rm, o);
128 }
129 // Increase the precision.
130 working_prec += increment;
131 increment = working_prec >> 1;
132 }
133}
134
135// Computes log_base(x) = ln(x) / ln(base) for `Float` `x` and `base`, following IEEE division of
136// the natural logs for every special case (so the function is total: no input value panics).
137fn log_base_float_base_helper(
138 x: &Float,
139 base: &Float,
140 prec: u64,
141 rm: RoundingMode,
142) -> (Float, Ordering) {
143 // ln of either operand is NaN when that operand is NaN or negative (negative finite or
144 // -infinity).
145 if x.is_nan() || base.is_nan() || *base < 0u32 || *x < 0u32 {
146 return (float_nan!(), Equal);
147 }
148 // x and base are each now +infinity, zero, or positive finite.
149 if base.is_infinite() {
150 // ln(base) = +infinity. ln(x) / +infinity = 0 for finite x (NaN for an infinite or zero x).
151 if x.is_infinite() || *x == 0u32 {
152 return (float_nan!(), Equal);
153 }
154 // 0, signed like ln(x): +0 for x >= 1, -0 for 0 < x < 1.
155 return if *x < 1u32 {
156 (Float::NEGATIVE_ZERO, Equal)
157 } else {
158 (Float::ZERO, Equal)
159 };
160 }
161 if *base == 0u32 {
162 // ln(base) = -infinity. ln(x) / -infinity = 0 for finite x (NaN for an infinite or zero x),
163 // sign-flipped: -0 for x >= 1, +0 for 0 < x < 1.
164 if x.is_infinite() || *x == 0u32 {
165 return (float_nan!(), Equal);
166 }
167 return if *x < 1u32 {
168 (Float::ZERO, Equal)
169 } else {
170 (Float::NEGATIVE_ZERO, Equal)
171 };
172 }
173 // base is positive finite.
174 if *base == 1u32 {
175 // ln(base) = +0. ln(x) / +0 = +-infinity by the sign of ln(x), or NaN for ln(x) = +-0.
176 if x.is_infinite() {
177 return (float_infinity!(), Equal); // ln(+inf) = +inf
178 }
179 if *x == 0u32 {
180 return (float_negative_infinity!(), Equal); // ln(0) = -inf
181 }
182 return if *x == 1u32 {
183 (float_nan!(), Equal) // +0 / +0
184 } else if *x > 1u32 {
185 (float_infinity!(), Equal)
186 } else {
187 (float_negative_infinity!(), Equal)
188 };
189 }
190 // base is positive finite and not 1.
191 if x.is_infinite() {
192 // ln(x) = +infinity. +infinity / ln(base): +infinity for base > 1, -infinity for base < 1.
193 return if *base < 1u32 {
194 (float_negative_infinity!(), Equal)
195 } else {
196 (float_infinity!(), Equal)
197 };
198 }
199 if *x == 0u32 {
200 // ln(x) = -infinity. -infinity / ln(base): -infinity for base > 1, +infinity for base < 1.
201 return if *base < 1u32 {
202 (float_infinity!(), Equal)
203 } else {
204 (float_negative_infinity!(), Equal)
205 };
206 }
207 // x and base are both positive finite, with base not 1.
208 log_base_float_base_normal(x, base, prec, rm)
209}
210
211impl Float {
212 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, rounding the result to
213 /// the specified precision and with the specified rounding mode. The [`Float`] is taken by
214 /// value and the base by reference. An [`Ordering`] is also returned, indicating whether the
215 /// rounded value is less than, equal to, or greater than the exact value. Although `NaN`s are
216 /// not comparable to any [`Float`], whenever this function returns a `NaN` it also returns
217 /// `Equal`.
218 ///
219 /// Unlike the integer- and rational-base logarithms, the base may be any [`Float`]: the
220 /// function is defined as $\ln x / \ln b$ for every pair of [`Float`]s, applying IEEE division
221 /// to the natural logs, and never panics on an input value. In particular a base in $(0,1)$
222 /// gives a (sign-flipped) logarithm, and the non-normal and degenerate bases follow the limits
223 /// below.
224 ///
225 /// This computes $\log_2 x / \log_2 b$, wrapping both logs in an extended exponent range so
226 /// that the quotient may overflow (base near 1) or underflow (x near 1) and be clamped exactly
227 /// once.
228 ///
229 /// See [`RoundingMode`] for a description of the possible rounding modes.
230 ///
231 /// $$
232 /// f(x,b,p,m) = \log_b x+\varepsilon.
233 /// $$
234 /// - If $\log_b x$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or assumed to be
235 /// 0.
236 /// - If $\log_b x$ is finite and nonzero, and $m$ is not `Nearest`, then $|\varepsilon| <
237 /// 2^{\lfloor\log_2 |\log_b x|\rfloor-p+1}$.
238 /// - If $\log_b x$ is finite and nonzero, and $m$ is `Nearest`, then $|\varepsilon| \leq
239 /// 2^{\lfloor\log_2 |\log_b x|\rfloor-p}$.
240 ///
241 /// If the output has a precision, it is `prec`.
242 ///
243 /// Special cases (with $b$ the base):
244 /// - $f(\text{NaN},b,p,m)=\text{NaN}$, and $f(x,\text{NaN},p,m)=\text{NaN}$
245 /// - $f(x,b,p,m)=\text{NaN}$ for $x<0$ or $b<0$ (including $\pm\infty$ where indicated below)
246 /// - $f(\infty,b,p,m)=\infty$ for $b>1$, and $-\infty$ for $0\leq b<1$
247 /// - $f(\pm0.0,b,p,m)=-\infty$ for $b>1$, and $\infty$ for $0<b<1$
248 /// - $f(1.0,b,p,m)=0$ (with the sign of $1/\ln b$)
249 /// - $f(x,\infty,p,m)=0$ for finite $x>0$ (and $\text{NaN}$ for $x\in\\{\pm\infty,\pm0.0\\}$)
250 /// - $f(x,\pm0.0,p,m)=0$ for finite $x>0$ (and $\text{NaN}$ for $x\in\\{\pm\infty,\pm0.0\\}$)
251 /// - $f(x,1.0,p,m)=\infty$ for $x>1$ or $x=\infty$, $-\infty$ for $0\leq x<1$, and $\text{NaN}$
252 /// for $x=1$
253 /// - $f(g^a,g^e,p,m)=a/e$ for a common rational $g$, rounded to precision $p$; the result is
254 /// exact if and only if $a/e$ is representable with precision $p$ (for example $\log_4
255 /// 8=3/2$)
256 ///
257 /// This function can both overflow (for a base near 1) and underflow (for an $x$ near 1).
258 ///
259 /// # Worst-case complexity
260 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
261 ///
262 /// $M(n, m) = O(n \log n + m \log m)$
263 ///
264 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
265 /// `max(self.significant_bits(), base.significant_bits())`.
266 ///
267 /// # Panics
268 /// Panics if `prec` is zero, or if `rm` is `Exact` but the result cannot be represented exactly
269 /// with the given precision.
270 ///
271 /// # Examples
272 /// ```
273 /// use malachite_base::rounding_modes::RoundingMode::*;
274 /// use malachite_float::Float;
275 /// use std::cmp::Ordering::*;
276 ///
277 /// let (log, o) = Float::from(8).log_base_float_base_prec_round(&Float::from(4), 10, Exact);
278 /// assert_eq!(log.to_string(), "1.5000"); // log_4(8) = 3/2
279 /// assert_eq!(o, Equal);
280 ///
281 /// let (log, o) = Float::from(4).log_base_float_base_prec_round(&Float::from(0.5), 10, Exact);
282 /// assert_eq!(log.to_string(), "-2.0000"); // log_{1/2}(4) = -2
283 /// assert_eq!(o, Equal);
284 /// ```
285 #[inline]
286 pub fn log_base_float_base_prec_round(
287 self,
288 base: &Self,
289 prec: u64,
290 rm: RoundingMode,
291 ) -> (Self, Ordering) {
292 assert_ne!(prec, 0);
293 log_base_float_base_helper(&self, base, prec, rm)
294 }
295
296 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, rounding the result to
297 /// the specified precision and with the specified rounding mode. Both are taken by reference.
298 /// An [`Ordering`] is also returned, indicating whether the rounded value is less than, equal
299 /// to, or greater than the exact value.
300 ///
301 /// See [`Float::log_base_float_base_prec_round`] for details, special cases, and a description
302 /// of the rounding behavior.
303 ///
304 /// # Worst-case complexity
305 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
306 ///
307 /// $M(n, m) = O(n \log n + m \log m)$
308 ///
309 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
310 /// `max(self.significant_bits(), base.significant_bits())`.
311 ///
312 /// # Panics
313 /// Panics if `prec` is zero, or if `rm` is `Exact` but the result cannot be represented exactly
314 /// with the given precision.
315 ///
316 /// # Examples
317 /// ```
318 /// use malachite_base::num::basic::traits::Two;
319 /// use malachite_base::rounding_modes::RoundingMode::*;
320 /// use malachite_float::Float;
321 /// use std::cmp::Ordering::*;
322 ///
323 /// let (log, o) = (&Float::from(8)).log_base_float_base_prec_round_ref(&Float::TWO, 10, Exact);
324 /// assert_eq!(log.to_string(), "3.0000"); // log_2(8) = 3
325 /// assert_eq!(o, Equal);
326 ///
327 /// let (log, o) = (&Float::TWO).log_base_float_base_prec_round_ref(&Float::from(4), 10, Exact);
328 /// assert_eq!(log.to_string(), "0.50000"); // log_4(2) = 1/2
329 /// assert_eq!(o, Equal);
330 /// ```
331 #[inline]
332 pub fn log_base_float_base_prec_round_ref(
333 &self,
334 base: &Self,
335 prec: u64,
336 rm: RoundingMode,
337 ) -> (Self, Ordering) {
338 assert_ne!(prec, 0);
339 log_base_float_base_helper(self, base, prec, rm)
340 }
341
342 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, rounding the result to
343 /// the nearest value of the specified precision. The [`Float`] is taken by value and the base
344 /// by reference. An [`Ordering`] is also returned.
345 ///
346 /// See [`Float::log_base_float_base_prec_round`] for details and special cases.
347 ///
348 /// # Worst-case complexity
349 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
350 ///
351 /// $M(n, m) = O(n \log n + m \log m)$
352 ///
353 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
354 /// `max(self.significant_bits(), base.significant_bits())`.
355 ///
356 /// # Panics
357 /// Panics if `prec` is zero.
358 ///
359 /// # Examples
360 /// ```
361 /// use malachite_float::Float;
362 /// use std::cmp::Ordering::*;
363 ///
364 /// let (log, o) = Float::from(8).log_base_float_base_prec(&Float::from(4), 10);
365 /// assert_eq!(log.to_string(), "1.5000"); // log_4(8) = 3/2
366 /// assert_eq!(o, Equal);
367 /// ```
368 #[inline]
369 pub fn log_base_float_base_prec(self, base: &Self, prec: u64) -> (Self, Ordering) {
370 self.log_base_float_base_prec_round(base, prec, Nearest)
371 }
372
373 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, rounding the result to
374 /// the nearest value of the specified precision. Both are taken by reference. An [`Ordering`]
375 /// is also returned.
376 ///
377 /// See [`Float::log_base_float_base_prec_round`] for details and special cases.
378 ///
379 /// # Worst-case complexity
380 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
381 ///
382 /// $M(n, m) = O(n \log n + m \log m)$
383 ///
384 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
385 /// `max(self.significant_bits(), base.significant_bits())`.
386 ///
387 /// # Panics
388 /// Panics if `prec` is zero.
389 ///
390 /// # Examples
391 /// ```
392 /// use malachite_float::Float;
393 /// use std::cmp::Ordering::*;
394 ///
395 /// let (log, o) = (&Float::from(8)).log_base_float_base_prec_ref(&Float::from(4), 10);
396 /// assert_eq!(log.to_string(), "1.5000"); // log_4(8) = 3/2
397 /// assert_eq!(o, Equal);
398 /// ```
399 #[inline]
400 pub fn log_base_float_base_prec_ref(&self, base: &Self, prec: u64) -> (Self, Ordering) {
401 self.log_base_float_base_prec_round_ref(base, prec, Nearest)
402 }
403
404 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, rounding the result to
405 /// the precision of the input and with the specified rounding mode. The [`Float`] is taken by
406 /// value and the base by reference. An [`Ordering`] is also returned.
407 ///
408 /// See [`Float::log_base_float_base_prec_round`] for details and special cases.
409 ///
410 /// # Worst-case complexity
411 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
412 ///
413 /// $M(n, m) = O(n \log n + m \log m)$
414 ///
415 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
416 /// `base.significant_bits()`.
417 ///
418 /// # Panics
419 /// Panics if `rm` is `Exact` but the result cannot be represented exactly with the input's
420 /// precision.
421 ///
422 /// # Examples
423 /// ```
424 /// use malachite_base::rounding_modes::RoundingMode::*;
425 /// use malachite_float::Float;
426 /// use std::cmp::Ordering::*;
427 ///
428 /// let (log, o) = Float::from(81).log_base_float_base_round(&Float::from(3), Exact);
429 /// assert_eq!(log.to_string(), "4.000"); // log_3(81) = 4
430 /// assert_eq!(o, Equal);
431 /// ```
432 #[inline]
433 pub fn log_base_float_base_round(self, base: &Self, rm: RoundingMode) -> (Self, Ordering) {
434 let prec = self.significant_bits();
435 self.log_base_float_base_prec_round(base, prec, rm)
436 }
437
438 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, rounding the result to
439 /// the precision of the input and with the specified rounding mode. Both are taken by
440 /// reference. An [`Ordering`] is also returned.
441 ///
442 /// See [`Float::log_base_float_base_prec_round`] for details and special cases.
443 ///
444 /// # Worst-case complexity
445 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
446 ///
447 /// $M(n, m) = O(n \log n + m \log m)$
448 ///
449 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
450 /// `base.significant_bits()`.
451 ///
452 /// # Panics
453 /// Panics if `rm` is `Exact` but the result cannot be represented exactly with the input's
454 /// precision.
455 ///
456 /// # Examples
457 /// ```
458 /// use malachite_base::rounding_modes::RoundingMode::*;
459 /// use malachite_float::Float;
460 /// use std::cmp::Ordering::*;
461 ///
462 /// let (log, o) = (&Float::from(81)).log_base_float_base_round_ref(&Float::from(3), Exact);
463 /// assert_eq!(log.to_string(), "4.000"); // log_3(81) = 4
464 /// assert_eq!(o, Equal);
465 /// ```
466 #[inline]
467 pub fn log_base_float_base_round_ref(&self, base: &Self, rm: RoundingMode) -> (Self, Ordering) {
468 self.log_base_float_base_prec_round_ref(base, self.significant_bits(), rm)
469 }
470
471 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, in place, rounding the
472 /// result to the specified precision and with the specified rounding mode. The base is taken by
473 /// reference. An [`Ordering`] is returned.
474 ///
475 /// See [`Float::log_base_float_base_prec_round`] for details and special cases.
476 ///
477 /// # Worst-case complexity
478 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
479 ///
480 /// $M(n, m) = O(n \log n + m \log m)$
481 ///
482 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
483 /// `max(self.significant_bits(), base.significant_bits())`.
484 ///
485 /// # Panics
486 /// Panics if `prec` is zero, or if `rm` is `Exact` but the result cannot be represented exactly
487 /// with the given precision.
488 ///
489 /// # Examples
490 /// ```
491 /// use malachite_base::rounding_modes::RoundingMode::*;
492 /// use malachite_float::Float;
493 /// use std::cmp::Ordering::*;
494 ///
495 /// let mut x = Float::from(8);
496 /// assert_eq!(
497 /// x.log_base_float_base_prec_round_assign(&Float::from(4), 10, Exact),
498 /// Equal
499 /// );
500 /// assert_eq!(x.to_string(), "1.5000"); // log_4(8) = 3/2
501 /// ```
502 #[inline]
503 pub fn log_base_float_base_prec_round_assign(
504 &mut self,
505 base: &Self,
506 prec: u64,
507 rm: RoundingMode,
508 ) -> Ordering {
509 let (result, o) = core::mem::take(self).log_base_float_base_prec_round(base, prec, rm);
510 *self = result;
511 o
512 }
513
514 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, in place, rounding the
515 /// result to the nearest value of the specified precision. The base is taken by reference. An
516 /// [`Ordering`] is returned.
517 ///
518 /// See [`Float::log_base_float_base_prec_round`] for details and special cases.
519 ///
520 /// # Worst-case complexity
521 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
522 ///
523 /// $M(n, m) = O(n \log n + m \log m)$
524 ///
525 /// where $T$ is time, $M$ is additional memory, $n$ is `prec`, and $m$ is
526 /// `max(self.significant_bits(), base.significant_bits())`.
527 ///
528 /// # Panics
529 /// Panics if `prec` is zero.
530 ///
531 /// # Examples
532 /// ```
533 /// use malachite_float::Float;
534 ///
535 /// let mut x = Float::from(8);
536 /// x.log_base_float_base_prec_assign(&Float::from(4), 10);
537 /// assert_eq!(x.to_string(), "1.5000"); // log_4(8) = 3/2
538 /// ```
539 #[inline]
540 pub fn log_base_float_base_prec_assign(&mut self, base: &Self, prec: u64) -> Ordering {
541 self.log_base_float_base_prec_round_assign(base, prec, Nearest)
542 }
543
544 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, in place, rounding the
545 /// result to the precision of the input and with the specified rounding mode. The base is taken
546 /// by reference. An [`Ordering`] is returned.
547 ///
548 /// See [`Float::log_base_float_base_prec_round`] for details and special cases.
549 ///
550 /// # Worst-case complexity
551 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
552 ///
553 /// $M(n, m) = O(n \log n + m \log m)$
554 ///
555 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
556 /// `base.significant_bits()`.
557 ///
558 /// # Panics
559 /// Panics if `rm` is `Exact` but the result cannot be represented exactly with the input's
560 /// precision.
561 ///
562 /// # Examples
563 /// ```
564 /// use malachite_base::rounding_modes::RoundingMode::*;
565 /// use malachite_float::Float;
566 ///
567 /// let mut x = Float::from(81);
568 /// x.log_base_float_base_round_assign(&Float::from(3), Exact);
569 /// assert_eq!(x.to_string(), "4.000"); // log_3(81) = 4
570 /// ```
571 #[inline]
572 pub fn log_base_float_base_round_assign(&mut self, base: &Self, rm: RoundingMode) -> Ordering {
573 let prec = self.significant_bits();
574 self.log_base_float_base_prec_round_assign(base, prec, rm)
575 }
576}
577
578impl LogBase<Self> for Float {
579 type Output = Self;
580
581 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, rounding the result to
582 /// the nearest value of the input's precision. Both are taken by value.
583 ///
584 /// See [`Float::log_base_float_base_prec_round`] for special cases.
585 ///
586 /// # Worst-case complexity
587 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
588 ///
589 /// $M(n, m) = O(n \log n + m \log m)$
590 ///
591 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
592 /// `base.significant_bits()`.
593 ///
594 /// # Examples
595 /// ```
596 /// use malachite_base::num::arithmetic::traits::LogBase;
597 /// use malachite_float::Float;
598 ///
599 /// assert_eq!(
600 /// Float::from(81).log_base(Float::from(3)).to_string(),
601 /// "4.000"
602 /// ); // log_3(81) = 4
603 /// assert_eq!(Float::from(9).log_base(Float::from(3)).to_string(), "2.00"); // log_3(9) = 2
604 /// ```
605 #[inline]
606 fn log_base(self, base: Self) -> Self {
607 let prec = self.significant_bits();
608 self.log_base_float_base_prec_round(&base, prec, Nearest).0
609 }
610}
611
612impl LogBase<&Float> for &Float {
613 type Output = Float;
614
615 /// Computes $\log_b x$, where $x$ and the base $b$ are both [`Float`]s, rounding the result to
616 /// the nearest value of the input's precision. Both are taken by reference.
617 ///
618 /// See [`Float::log_base_float_base_prec_round`] for special cases.
619 ///
620 /// # Worst-case complexity
621 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
622 ///
623 /// $M(n, m) = O(n \log n + m \log m)$
624 ///
625 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
626 /// `base.significant_bits()`.
627 ///
628 /// # Examples
629 /// ```
630 /// use malachite_base::num::arithmetic::traits::LogBase;
631 /// use malachite_float::Float;
632 ///
633 /// assert_eq!(
634 /// (&Float::from(81)).log_base(&Float::from(3)).to_string(),
635 /// "4.000"
636 /// ); // log_3(81)=4
637 /// assert_eq!(
638 /// (&Float::from(9)).log_base(&Float::from(3)).to_string(),
639 /// "2.00"
640 /// ); // log_3(9)=2
641 /// ```
642 #[inline]
643 fn log_base(self, base: &Float) -> Float {
644 self.log_base_float_base_prec_round_ref(base, self.significant_bits(), Nearest)
645 .0
646 }
647}
648
649impl LogBaseAssign<&Self> for Float {
650 /// Replaces a [`Float`] $x$ with $\log_b x$, where the base $b$ is a [`Float`], rounding the
651 /// result to the nearest value of the input's precision. The base is taken by reference.
652 ///
653 /// See [`Float::log_base_float_base_prec_round`] for special cases.
654 ///
655 /// # Worst-case complexity
656 /// $T(n, m) = O(n (\log n)^2 \log\log n + m \log m \log\log m)$
657 ///
658 /// $M(n, m) = O(n \log n + m \log m)$
659 ///
660 /// where $T$ is time, $M$ is additional memory, $n$ is the precision of the input, and $m$ is
661 /// `base.significant_bits()`.
662 ///
663 /// # Examples
664 /// ```
665 /// use malachite_base::num::arithmetic::traits::LogBaseAssign;
666 /// use malachite_float::Float;
667 ///
668 /// let mut x = Float::from(81);
669 /// x.log_base_assign(&Float::from(3));
670 /// assert_eq!(x.to_string(), "4.000"); // log_3(81) = 4
671 /// ```
672 #[inline]
673 fn log_base_assign(&mut self, base: &Self) {
674 let prec = self.significant_bits();
675 self.log_base_float_base_prec_round_assign(base, prec, Nearest);
676 }
677}
678
679/// Computes $\log_b x$, the base-$b$ logarithm of a primitive float, where the base $b$ is also a
680/// primitive float, returning a primitive float result. Using this function is more accurate than
681/// computing the logarithm using the standard library, whose logarithm functions are not always
682/// correctly rounded.
683///
684/// Unlike the integer- and rational-base logarithms, the base may be any primitive float: the
685/// function is defined as $\ln x / \ln b$ and never panics on an input value. A base in $(0,1)$
686/// gives a (sign-flipped) logarithm, and the non-normal and degenerate bases follow the limits
687/// below.
688///
689/// $$
690/// f(x,b) = \log_b x+\varepsilon.
691/// $$
692/// - If $\log_b x$ is infinite, zero, or `NaN`, $\varepsilon$ may be ignored or assumed to be 0.
693/// - If $\log_b x$ is finite and nonzero, then $|\varepsilon| < 2^{\lfloor\log_2 |\log_b
694/// x|\rfloor-p}$, where $p$ is precision of the output (typically 24 if `T` is a [`f32`] and 53
695/// if `T` is a [`f64`], but less if the output is subnormal).
696///
697/// Special cases (with $b$ the base):
698/// - $f(\text{NaN},b)=\text{NaN}$, and $f(x,\text{NaN})=\text{NaN}$
699/// - $f(x,b)=\text{NaN}$ for $x<0$ or $b<0$
700/// - $f(\infty,b)=\infty$ for $b>1$, and $-\infty$ for $0\leq b<1$
701/// - $f(\pm0.0,b)=-\infty$ for $b>1$, and $\infty$ for $0<b<1$
702/// - $f(1.0,b)=0.0$ (with the sign of $1/\ln b$)
703/// - $f(x,\infty)=0.0$ for finite $x>0$ (and $\text{NaN}$ for $x\in\\{\pm\infty,\pm0.0\\}$)
704/// - $f(x,\pm0.0)=0.0$ for finite $x>0$ (and $\text{NaN}$ for $x\in\\{\pm\infty,\pm0.0\\}$)
705/// - $f(x,1.0)=\infty$ for $x>1$ or $x=\infty$, $-\infty$ for $0\leq x<1$, and $\text{NaN}$ for
706/// $x=1$
707///
708/// This function can both overflow (for a base near 1) and underflow (for an $x$ near 1).
709///
710/// # Worst-case complexity
711/// Constant time and additional memory.
712///
713/// # Examples
714/// ```
715/// use malachite_base::num::float::NiceFloat;
716/// use malachite_float::float::arithmetic::log_base_float_base::*;
717///
718/// // log_4(8) = 3/2
719/// assert_eq!(
720/// NiceFloat(primitive_float_log_base_float_base(8.0f32, 4.0)),
721/// NiceFloat(1.5)
722/// );
723/// // log_(1/2)(4) = -2
724/// assert_eq!(
725/// NiceFloat(primitive_float_log_base_float_base(4.0f32, 0.5)),
726/// NiceFloat(-2.0)
727/// );
728/// // log_10(50)
729/// assert_eq!(
730/// NiceFloat(primitive_float_log_base_float_base(50.0f32, 10.0)),
731/// NiceFloat(1.69897)
732/// );
733/// // log_inf(8) = 0
734/// assert_eq!(
735/// NiceFloat(primitive_float_log_base_float_base(8.0f32, f32::INFINITY)),
736/// NiceFloat(0.0)
737/// );
738/// assert!(primitive_float_log_base_float_base(-1.0f32, 10.0).is_nan());
739/// assert!(primitive_float_log_base_float_base(8.0f32, f32::NAN).is_nan());
740/// ```
741#[inline]
742#[allow(clippy::type_repetition_in_bounds)]
743pub fn primitive_float_log_base_float_base<T: PrimitiveFloat>(x: T, base: T) -> T
744where
745 Float: From<T> + PartialOrd<T>,
746 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
747{
748 emulate_float_float_to_float_fn(
749 |x, base, prec| x.log_base_float_base_prec(&base, prec),
750 x,
751 base,
752 )
753}