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}