Skip to main content

malachite_float/constants/
log_10_e.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::Float;
10use core::cmp::Ordering;
11use malachite_base::num::arithmetic::traits::Reciprocal;
12use malachite_base::num::basic::integers::PrimitiveInt;
13use malachite_base::rounding_modes::RoundingMode::{self, *};
14use malachite_nz::natural::arithmetic::float_extras::float_can_round;
15use malachite_nz::platform::Limb;
16
17impl Float {
18    /// Returns an approximation of the base-10 logarithm of $e$, with the given precision and
19    /// rounded using the given [`RoundingMode`]. An [`Ordering`] is also returned, indicating
20    /// whether the rounded value is less than or greater than the exact value of the constant.
21    /// (Since the constant is irrational, the rounded value is never equal to the exact value.)
22    ///
23    /// $$
24    /// x = \log_{10} e+\varepsilon.
25    /// $$
26    /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{-p-1}$.
27    /// - If $m$ is `Nearest`, then $|\varepsilon| < 2^{-p-2}$.
28    ///
29    /// The constant is irrational and transcendental.
30    ///
31    /// The output has precision `prec`.
32    ///
33    /// # Worst-case complexity
34    /// $T(n) = O(n (\log n)^2 \log\log n)$
35    ///
36    /// $M(n) = O(n (\log n)^2)$
37    ///
38    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
39    ///
40    /// # Panics
41    /// Panics if `prec` is zero or if `rm` is `Exact`.
42    ///
43    /// # Examples
44    /// ```
45    /// use malachite_base::rounding_modes::RoundingMode::*;
46    /// use malachite_float::Float;
47    /// use std::cmp::Ordering::*;
48    ///
49    /// let (l, o) = Float::log_10_e_prec_round(100, Floor);
50    /// assert_eq!(l.to_string(), "0.4342944819032518276511289189163");
51    /// assert_eq!(o, Less);
52    ///
53    /// let (l, o) = Float::log_10_e_prec_round(100, Ceiling);
54    /// assert_eq!(l.to_string(), "0.4342944819032518276511289189167");
55    /// assert_eq!(o, Greater);
56    /// ```
57    pub fn log_10_e_prec_round(prec: u64, rm: RoundingMode) -> (Self, Ordering) {
58        let mut working_prec = prec + 10;
59        let mut increment = Limb::WIDTH;
60        loop {
61            let log_10_e = Self::ln_10_prec_round(working_prec, Floor).0.reciprocal();
62            // As with log_2_e: since we rounded ln_10 down, the absolute error of the inverse is
63            // bounded by (c_w + 2c_uk_u)ulp(log_e(10)) <= 4ulp(log_e(10)).
64            if float_can_round(
65                log_10_e.significand_ref().unwrap(),
66                working_prec - 2,
67                prec,
68                rm,
69            ) {
70                return Self::from_float_prec_round(log_10_e, prec, rm);
71            }
72            working_prec += increment;
73            increment = working_prec >> 1;
74        }
75    }
76
77    /// Returns an approximation of the base-10 logarithm of $e$, with the given precision and
78    /// rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also returned,
79    /// indicating whether the rounded value is less than or greater than the exact value of the
80    /// constant. (Since the constant is irrational, the rounded value is never equal to the exact
81    /// value.)
82    ///
83    /// $$
84    /// x = \log_{10} e+\varepsilon.
85    /// $$
86    /// - $|\varepsilon| < 2^{-p-2}$.
87    ///
88    /// The constant is irrational and transcendental.
89    ///
90    /// The output has precision `prec`.
91    ///
92    /// # Worst-case complexity
93    /// $T(n) = O(n (\log n)^2 \log\log n)$
94    ///
95    /// $M(n) = O(n (\log n)^2)$
96    ///
97    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
98    ///
99    /// # Panics
100    /// Panics if `prec` is zero.
101    ///
102    /// # Examples
103    /// ```
104    /// use malachite_float::Float;
105    /// use std::cmp::Ordering::*;
106    ///
107    /// let (l, o) = Float::log_10_e_prec(1);
108    /// assert_eq!(l.to_string(), "0.5");
109    /// assert_eq!(o, Greater);
110    ///
111    /// let (l, o) = Float::log_10_e_prec(10);
112    /// assert_eq!(l.to_string(), "0.4341");
113    /// assert_eq!(o, Less);
114    ///
115    /// let (l, o) = Float::log_10_e_prec(100);
116    /// assert_eq!(l.to_string(), "0.4342944819032518276511289189167");
117    /// assert_eq!(o, Greater);
118    /// ```
119    #[inline]
120    pub fn log_10_e_prec(prec: u64) -> (Self, Ordering) {
121        Self::log_10_e_prec_round(prec, Nearest)
122    }
123}