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