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