malachite_float/constants/log_2_e.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MPFR Library.
4//
5// Copyright 1999, 2001-2024 Free Software Foundation, Inc.
6//
7// Contributed by the AriC and Caramba projects, INRIA.
8//
9// This file is part of Malachite.
10//
11// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
12// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
13// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
14
15use crate::Float;
16use core::cmp::Ordering;
17use malachite_base::num::arithmetic::traits::Reciprocal;
18use malachite_base::num::basic::integers::PrimitiveInt;
19use malachite_base::rounding_modes::RoundingMode::{self, *};
20use malachite_nz::natural::arithmetic::float_extras::float_can_round;
21use malachite_nz::platform::Limb;
22
23impl Float {
24 /// Returns an approximation of the base-2 logarithm of $e$, with the given precision and
25 /// rounded using the given [`RoundingMode`]. An [`Ordering`] is also returned, indicating
26 /// whether the rounded value is less than or greater than the exact value of the constant.
27 /// (Since the constant is irrational, the rounded value is never equal to the exact value.)
28 ///
29 /// $$
30 /// x = \log_2 e+\varepsilon.
31 /// $$
32 /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{-p+1}$.
33 /// - If $m$ is `Nearest`, then $|\varepsilon| < 2^{-p}$.
34 ///
35 /// The constant is irrational and transcendental.
36 ///
37 /// The output has precision `prec`.
38 ///
39 /// # Worst-case complexity
40 /// $T(n) = O(n (\log n)^2 \log\log n)$
41 ///
42 /// $M(n) = O(n (\log n)^2)$
43 ///
44 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
45 ///
46 /// # Panics
47 /// Panics if `prec` is zero or if `rm` is `Exact`.
48 ///
49 /// # Examples
50 /// ```
51 /// use malachite_base::rounding_modes::RoundingMode::*;
52 /// use malachite_float::Float;
53 /// use std::cmp::Ordering::*;
54 ///
55 /// let (log_2_e, o) = Float::log_2_e_prec_round(100, Floor);
56 /// assert_eq!(log_2_e.to_string(), "1.442695040888963407359924681001");
57 /// assert_eq!(o, Less);
58 ///
59 /// let (log_2_e, o) = Float::log_2_e_prec_round(100, Ceiling);
60 /// assert_eq!(log_2_e.to_string(), "1.442695040888963407359924681003");
61 /// assert_eq!(o, Greater);
62 /// ```
63 pub fn log_2_e_prec_round(prec: u64, rm: RoundingMode) -> (Self, Ordering) {
64 let mut working_prec = prec + 10;
65 let mut increment = Limb::WIDTH;
66 loop {
67 let log_2_e = Self::ln_2_prec_round(working_prec, Floor).0.reciprocal();
68 // See algorithms.tex. Since we rounded down when computing ln_2, the absolute error of
69 // the inverse is bounded by (c_w + 2c_uk_u)ulp(log_e(2)) <= 4ulp(log_e(2)).
70 if float_can_round(
71 log_2_e.significand_ref().unwrap(),
72 working_prec - 2,
73 prec,
74 rm,
75 ) {
76 return Self::from_float_prec_round(log_2_e, prec, rm);
77 }
78 working_prec += increment;
79 increment = working_prec >> 1;
80 }
81 }
82
83 /// Returns an approximation of the base-2 logarithm of $e$, with the given precision and
84 /// rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also returned,
85 /// indicating whether the rounded value is less than or greater than the exact value of the
86 /// constant. (Since the constant is irrational, the rounded value is never equal to the exact
87 /// value.)
88 ///
89 /// $$
90 /// x = \log_2 e+\varepsilon.
91 /// $$
92 /// - $|\varepsilon| < 2^{-p}$.
93 ///
94 /// The constant is irrational and transcendental.
95 ///
96 /// The output has precision `prec`.
97 ///
98 /// # Worst-case complexity
99 /// $T(n) = O(n (\log n)^2 \log\log n)$
100 ///
101 /// $M(n) = O(n (\log n)^2)$
102 ///
103 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
104 ///
105 /// # Panics
106 /// Panics if `prec` is zero.
107 ///
108 /// # Examples
109 /// ```
110 /// use malachite_float::Float;
111 /// use std::cmp::Ordering::*;
112 ///
113 /// let (log_2_e, o) = Float::log_2_e_prec(1);
114 /// assert_eq!(log_2_e.to_string(), "1.0");
115 /// assert_eq!(o, Less);
116 ///
117 /// let (log_2_e, o) = Float::log_2_e_prec(10);
118 /// assert_eq!(log_2_e.to_string(), "1.443");
119 /// assert_eq!(o, Greater);
120 ///
121 /// let (log_2_e, o) = Float::log_2_e_prec(100);
122 /// assert_eq!(log_2_e.to_string(), "1.442695040888963407359924681003");
123 /// assert_eq!(o, Greater);
124 /// ```
125 #[inline]
126 pub fn log_2_e_prec(prec: u64) -> (Self, Ordering) {
127 Self::log_2_e_prec_round(prec, Nearest)
128 }
129}