malachite_float/float/constants/liouvilles_constant.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, emulate_constant_to_float_fn};
10use core::cmp::Ordering;
11use malachite_base::num::arithmetic::traits::SaturatingMulAssign;
12use malachite_base::num::basic::floats::PrimitiveFloat;
13use malachite_base::num::conversion::traits::{ExactFrom, RoundingFrom};
14use malachite_base::rounding_modes::RoundingMode::{self, Nearest};
15
16// The digits of Liouville's constant in the given base: 1 at every position that is a factorial, 0
17// everywhere else. The positions are 1-indexed, so both 1! and 2! contribute a 1, making the
18// constant begin 0.11000100....
19//
20// The multiplication saturates rather than overflowing, which cannot be observed: 21! already
21// exceeds a `u64`, and reaching that position would mean reading more digits than any precision
22// could ask for.
23fn liouvilles_digits() -> impl Iterator<Item = u64> {
24 let mut position = 0u64;
25 let mut factorial = 1u64;
26 let mut index = 1u64;
27 core::iter::from_fn(move || {
28 position += 1;
29 Some(if position == factorial {
30 index += 1;
31 factorial.saturating_mul_assign(index);
32 1
33 } else {
34 0
35 })
36 })
37}
38
39impl Float {
40 /// Returns an approximation of Liouville's constant in a given base, with the given precision
41 /// and rounded using the given [`RoundingMode`]. An [`Ordering`] is also returned, indicating
42 /// whether the rounded value is less than or greater than the exact value of the constant.
43 /// (Since the constant is irrational, the rounded value is never equal to the exact value.)
44 ///
45 /// Liouville's constant in base $b$ has a digit of 1 at every position that is a factorial and
46 /// a digit of 0 everywhere else. That is,
47 /// $$
48 /// L_b = \sum_{n=1}^\infty b^{-n!}+\varepsilon.
49 /// $$
50 /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{\lfloor\log_2 L_b\rfloor-p+1}$.
51 /// - If $m$ is `Nearest`, then $|\varepsilon| < 2^{\lfloor\log_2 L_b\rfloor-p}$.
52 ///
53 /// Base 10 gives the classical constant, $0.110001000000000000000001\ldots$, the first number
54 /// proven transcendental. The constant is transcendental in every base, being a Liouville
55 /// number: its factorial-spaced digits make it approximable by rationals far too well for an
56 /// algebraic number.
57 ///
58 /// The output has precision `prec`.
59 ///
60 /// # Worst-case complexity
61 /// $T(n) = O(n (\log n)^2 \log\log n)$
62 ///
63 /// $M(n) = O(n \log n)$
64 ///
65 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
66 ///
67 /// # Panics
68 /// Panics if `base` is less than 2, if `prec` is zero, or if `rm` is `Exact`.
69 ///
70 /// # Examples
71 /// ```
72 /// use malachite_base::rounding_modes::RoundingMode::*;
73 /// use malachite_float::Float;
74 /// use std::cmp::Ordering::*;
75 ///
76 /// // In base 2 the constant has a 1 at every factorial position -- 1, 2, 6, 24, ... -- and a
77 /// // 0 everywhere else, which the binary representation shows directly.
78 /// let (x, o) = Float::liouvilles_constant_base_prec_round(2, 64, Floor);
79 /// assert_eq!(x.to_string(), "0.765625059604644775391");
80 /// assert_eq!(
81 /// format!("{x:#b}"),
82 /// "0b0.1100010000000000000000010000000000000000000000000000000000000000"
83 /// );
84 /// assert_eq!(o, Less);
85 ///
86 /// let (x, o) = Float::liouvilles_constant_base_prec_round(2, 64, Ceiling);
87 /// assert_eq!(x.to_string(), "0.765625059604644775445");
88 /// assert_eq!(
89 /// format!("{x:#b}"),
90 /// "0b0.1100010000000000000000010000000000000000000000000000000000000001"
91 /// );
92 /// assert_eq!(o, Greater);
93 /// ```
94 #[inline]
95 pub fn liouvilles_constant_base_prec_round(
96 base: u64,
97 prec: u64,
98 rm: RoundingMode,
99 ) -> (Self, Ordering) {
100 Self::non_dyadic_from_digits_prec_round(liouvilles_digits(), base, prec, rm)
101 }
102
103 /// Returns an approximation of Liouville's constant in a given base, with the given precision
104 /// and rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also returned,
105 /// indicating whether the rounded value is less than or greater than the exact value.
106 ///
107 /// See [`liouvilles_constant_base_prec_round`](Float::liouvilles_constant_base_prec_round) for
108 /// details.
109 ///
110 /// # Worst-case complexity
111 /// $T(n) = O(n (\log n)^2 \log\log n)$
112 ///
113 /// $M(n) = O(n \log n)$
114 ///
115 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
116 ///
117 /// # Panics
118 /// Panics if `base` is less than 2 or if `prec` is zero.
119 ///
120 /// # Examples
121 /// ```
122 /// use malachite_float::Float;
123 /// use std::cmp::Ordering::*;
124 ///
125 /// // In base 2 the 1s sit at the factorial positions 1, 2, 6, 24, ...
126 /// let (x, o) = Float::liouvilles_constant_base_prec(2, 64);
127 /// assert_eq!(x.to_string(), "0.765625059604644775391");
128 /// assert_eq!(
129 /// format!("{x:#b}"),
130 /// "0b0.1100010000000000000000010000000000000000000000000000000000000000"
131 /// );
132 /// assert_eq!(o, Less);
133 ///
134 /// // A base that is not a power of 2 takes the general path, where the digits cannot simply
135 /// // be read off.
136 /// let (x, o) = Float::liouvilles_constant_base_prec(3, 50);
137 /// assert_eq!(x.to_string(), "0.44581618656046818");
138 /// assert_eq!(o, Greater);
139 /// ```
140 #[inline]
141 pub fn liouvilles_constant_base_prec(base: u64, prec: u64) -> (Self, Ordering) {
142 Self::liouvilles_constant_base_prec_round(base, prec, Nearest)
143 }
144
145 /// Returns an approximation of Liouville's constant in base 10, with the given precision and
146 /// rounded using the given [`RoundingMode`]. An [`Ordering`] is also returned, indicating
147 /// whether the rounded value is less than or greater than the exact value of the constant.
148 /// (Since the constant is irrational, the rounded value is never equal to the exact value.)
149 ///
150 /// Liouville's constant has a decimal digit of 1 at every position that is a factorial and a
151 /// digit of 0 everywhere else, so it begins $0.110001000000000000000001\ldots$.
152 ///
153 /// $$
154 /// x = L = \sum_{n=1}^{\infty} 10^{-n!}+\varepsilon.
155 /// $$
156 /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{-p}$.
157 /// - If $m$ is `Nearest`, then $|\varepsilon| < 2^{-p-1}$.
158 ///
159 /// The constant is irrational and transcendental.
160 ///
161 /// The output has precision `prec`.
162 ///
163 /// This is the base-10 specialization of
164 /// [`liouvilles_constant_base_prec_round`](Float::liouvilles_constant_base_prec_round).
165 ///
166 /// # Worst-case complexity
167 /// $T(n) = O(n \log n \log\log n)$
168 ///
169 /// $M(n) = O(n \log n)$
170 ///
171 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
172 ///
173 /// # Panics
174 /// Panics if `prec` is zero or if `rm` is `Exact`.
175 ///
176 /// # Examples
177 /// ```
178 /// use malachite_base::rounding_modes::RoundingMode::*;
179 /// use malachite_float::Float;
180 /// use std::cmp::Ordering::*;
181 ///
182 /// let (x, o) = Float::liouvilles_constant_prec_round(100, Floor);
183 /// assert_eq!(x.to_string(), "0.11000100000000000000000099999997");
184 /// assert_eq!(o, Less);
185 ///
186 /// let (x, o) = Float::liouvilles_constant_prec_round(100, Ceiling);
187 /// assert_eq!(x.to_string(), "0.11000100000000000000000100000007");
188 /// assert_eq!(o, Greater);
189 /// ```
190 #[inline]
191 pub fn liouvilles_constant_prec_round(prec: u64, rm: RoundingMode) -> (Self, Ordering) {
192 Self::liouvilles_constant_base_prec_round(10, prec, rm)
193 }
194
195 /// Returns an approximation of Liouville's constant in base 10, with the given precision and
196 /// rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also returned,
197 /// indicating whether the rounded value is less than or greater than the exact value of the
198 /// constant. (Since the constant is irrational, the rounded value is never equal to the exact
199 /// value.)
200 ///
201 /// Liouville's constant has a decimal digit of 1 at every position that is a factorial and a
202 /// digit of 0 everywhere else, so it begins $0.110001000000000000000001\ldots$.
203 ///
204 /// $$
205 /// x = L = \sum_{n=1}^{\infty} 10^{-n!}+\varepsilon.
206 /// $$
207 /// - $|\varepsilon| < 2^{-p-1}$.
208 ///
209 /// The constant is irrational and transcendental.
210 ///
211 /// The output has precision `prec`.
212 ///
213 /// This is the base-10 specialization of
214 /// [`liouvilles_constant_base_prec`](Float::liouvilles_constant_base_prec).
215 ///
216 /// # Worst-case complexity
217 /// $T(n) = O(n \log n \log\log n)$
218 ///
219 /// $M(n) = O(n \log n)$
220 ///
221 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
222 ///
223 /// # Panics
224 /// Panics if `prec` is zero.
225 ///
226 /// # Examples
227 /// ```
228 /// use malachite_float::Float;
229 ///
230 /// let x = Float::liouvilles_constant_prec(100).0;
231 /// assert_eq!(x.to_string(), "0.11000100000000000000000099999997");
232 /// ```
233 #[inline]
234 pub fn liouvilles_constant_prec(prec: u64) -> (Self, Ordering) {
235 Self::liouvilles_constant_base_prec(10, prec)
236 }
237}
238
239/// Computes an approximation of Liouville's constant in a given base, returning a primitive float.
240///
241/// Liouville's constant in base $b$ has a digit of 1 at every position that is a factorial and a
242/// digit of 0 everywhere else.
243///
244/// $$
245/// L_b = \sum_{n=1}^{\infty} b^{-n!}.
246/// $$
247///
248/// The returned value is the one closest to the true constant; ties are broken by the
249/// round-half-to-even rule. Computing the constant this way is more accurate than summing its
250/// digits in primitive-float arithmetic, where each addition rounds.
251///
252/// $$
253/// f(b) = L_b+\varepsilon,
254/// $$
255/// where $|\varepsilon| < 2^{\lfloor\log_2 |L_b|\rfloor-p}$ and $p$ is the precision of the output
256/// (24 if `T` is a [`f32`] and 53 if `T` is a [`f64`]).
257///
258/// The constant lies in $[1/b,1)$, and $b$ is at most $2^{64}-1$, so this function can neither
259/// overflow nor underflow.
260///
261/// # Worst-case complexity
262/// Constant time and additional memory.
263///
264/// # Panics
265/// Panics if `base` is less than 2.
266///
267/// # Examples
268/// ```
269/// use malachite_base::num::float::NiceFloat;
270/// use malachite_float::float::constants::liouvilles_constant::*;
271///
272/// // The classical constant, 0.110001000000000000000001...
273/// assert_eq!(
274/// NiceFloat(primitive_float_liouvilles_constant_base::<f32>(10)),
275/// NiceFloat(0.110001)
276/// );
277/// assert_eq!(
278/// NiceFloat(primitive_float_liouvilles_constant_base::<f64>(10)),
279/// NiceFloat(0.110001)
280/// );
281/// // In base 2 the constant is 0.11000100000000000000000100...
282/// assert_eq!(
283/// NiceFloat(primitive_float_liouvilles_constant_base::<f64>(2)),
284/// NiceFloat(0.7656250596046448)
285/// );
286/// ```
287#[inline]
288#[allow(clippy::type_repetition_in_bounds)]
289pub fn primitive_float_liouvilles_constant_base<T: PrimitiveFloat>(base: u64) -> T
290where
291 Float: PartialOrd<T>,
292 for<'a> T: ExactFrom<&'a Float> + RoundingFrom<&'a Float>,
293{
294 emulate_constant_to_float_fn(|prec| Float::liouvilles_constant_base_prec(base, prec))
295}