malachite_float/constants/log_2_e.rs
1// Copyright © 2025 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 to 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 /// L = \log_2 e.
31 /// $$
32 ///
33 /// The constant is irrational and transcendental.
34 ///
35 /// The output has precision `prec`.
36 ///
37 /// # Worst-case complexity
38 /// $T(n) = O(n (\log n)^2 \log\log n)$
39 ///
40 /// $M(n) = O(n (\log n)^2)$
41 ///
42 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
43 ///
44 /// # Panics
45 /// Panics if `prec` is zero or if `rm` is `Exact`.
46 ///
47 /// # Examples
48 /// ```
49 /// use malachite_base::rounding_modes::RoundingMode::*;
50 /// use malachite_float::Float;
51 /// use std::cmp::Ordering::*;
52 ///
53 /// let (log_2_e, o) = Float::log_2_e_prec_round(100, Floor);
54 /// assert_eq!(log_2_e.to_string(), "1.442695040888963407359924681001");
55 /// assert_eq!(o, Less);
56 ///
57 /// let (log_2_e, o) = Float::log_2_e_prec_round(100, Ceiling);
58 /// assert_eq!(log_2_e.to_string(), "1.442695040888963407359924681003");
59 /// assert_eq!(o, Greater);
60 /// ```
61 pub fn log_2_e_prec_round(prec: u64, rm: RoundingMode) -> (Self, Ordering) {
62 let mut working_prec = prec + 10;
63 let mut increment = Limb::WIDTH;
64 loop {
65 let log_2_e = Self::ln_2_prec_round(working_prec, Floor).0.reciprocal();
66 // See algorithms.tex. Since we rounded down when computing ln_2, the absolute error of
67 // the square root is bounded by (c_w + 2c_uk_u)ulp(sqrt) <= 4ulp(sqrt).
68 if float_can_round(
69 log_2_e.significand_ref().unwrap(),
70 working_prec - 2,
71 prec,
72 rm,
73 ) {
74 return Self::from_float_prec_round(log_2_e, prec, rm);
75 }
76 working_prec += increment;
77 increment = working_prec >> 1;
78 }
79 }
80
81 /// Returns an approximation to the base-2 logarithm of $e$, with the given precision and
82 /// rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also returned,
83 /// indicating whether the rounded value is less than or greater than the exact value of the
84 /// constant. (Since the constant is irrational, the rounded value is never equal to the exact
85 /// value.)
86 ///
87 /// $$
88 /// L = \log_2 e.
89 /// $$
90 ///
91 /// The constant is irrational and transcendental.
92 ///
93 /// The output has precision `prec`.
94 ///
95 /// # Worst-case complexity
96 /// $T(n) = O(n (\log n)^2 \log\log n)$
97 ///
98 /// $M(n) = O(n (\log n)^2)$
99 ///
100 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
101 ///
102 /// # Panics
103 /// Panics if `prec` is zero.
104 ///
105 /// # Examples
106 /// ```
107 /// use malachite_float::Float;
108 /// use std::cmp::Ordering::*;
109 ///
110 /// let (log_2_e, o) = Float::log_2_e_prec(1);
111 /// assert_eq!(log_2_e.to_string(), "1.0");
112 /// assert_eq!(o, Less);
113 ///
114 /// let (log_2_e, o) = Float::log_2_e_prec(10);
115 /// assert_eq!(log_2_e.to_string(), "1.443");
116 /// assert_eq!(o, Greater);
117 ///
118 /// let (log_2_e, o) = Float::log_2_e_prec(100);
119 /// assert_eq!(log_2_e.to_string(), "1.442695040888963407359924681003");
120 /// assert_eq!(o, Greater);
121 /// ```
122 #[inline]
123 pub fn log_2_e_prec(prec: u64) -> (Self, Ordering) {
124 Self::log_2_e_prec_round(prec, Nearest)
125 }
126}