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}