malachite_float/constants/prouhet_thue_morse_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;
10use crate::InnerFloat::Finite;
11use alloc::vec;
12use core::cmp::Ordering::{self, *};
13use malachite_base::iterators::thue_morse_sequence;
14use malachite_base::num::arithmetic::traits::{NegModPowerOf2, PowerOf2};
15use malachite_base::num::basic::integers::PrimitiveInt;
16use malachite_base::num::basic::traits::OneHalf;
17use malachite_base::rounding_modes::RoundingMode::{self, *};
18use malachite_nz::natural::{Natural, bit_to_limb_count_ceiling};
19use malachite_nz::platform::Limb;
20
21#[cfg(feature = "32_bit_limbs")]
22const LIMB_0: Limb = 0xd32d2cd2;
23#[cfg(feature = "32_bit_limbs")]
24const LIMB_1: Limb = 0x2cd2d32c;
25
26#[cfg(not(feature = "32_bit_limbs"))]
27const LIMB_0: Limb = 0xd32d2cd32cd2d32c;
28#[cfg(not(feature = "32_bit_limbs"))]
29const LIMB_1: Limb = 0x2cd2d32cd32d2cd2;
30
31impl Float {
32 /// Returns an approximation of the Prouhet-Thue-Morse constant, with the given precision and
33 /// rounded using the given [`RoundingMode`]. An [`Ordering`] is also returned, indicating
34 /// whether the rounded value is less than or greater than the exact value of the constant.
35 /// (Since the constant is irrational, the rounded value is never equal to the exact value.)
36 ///
37 /// The Prouhet-Thue-Morse constant is the real number whose bits are the Thue-Morse sequence.
38 /// That is,
39 /// $$
40 /// \tau = \sum_{k=0}^\infty\frac{t_n}{2^{n+1}}+\varepsilon,
41 /// where $t_n$ is the Thue-Morse sequence.
42 /// $$
43 /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{-p-1}$.
44 /// - If $m$ is `Nearest`, then $|\varepsilon| < 2^{-p-2}$.
45 ///
46 /// An alternative expression, from <https://mathworld.wolfram.com/Thue-MorseConstant.html>, is
47 /// $$
48 /// \tau = \frac{1}{4}\left[2-\prod_{k=0}^\infty\left(1-\frac{1}{2^{2^k}}\right)\right].
49 /// $$
50 ///
51 /// The constant is irrational and transcendental.
52 ///
53 /// The output has precision `prec`.
54 ///
55 /// # Worst-case complexity
56 /// $T(n) = O(n)$
57 ///
58 /// $M(n) = O(n)$
59 ///
60 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
61 ///
62 /// # Panics
63 /// Panics if `prec` is zero or if `rm` is `Exact`.
64 ///
65 /// # Examples
66 /// ```
67 /// use malachite_base::rounding_modes::RoundingMode::*;
68 /// use malachite_float::Float;
69 /// use std::cmp::Ordering::*;
70 ///
71 /// let (tmc, o) = Float::prouhet_thue_morse_constant_prec_round(100, Floor);
72 /// assert_eq!(tmc.to_string(), "0.4124540336401075977833613682584");
73 /// assert_eq!(o, Less);
74 ///
75 /// let (tmc, o) = Float::prouhet_thue_morse_constant_prec_round(100, Ceiling);
76 /// assert_eq!(tmc.to_string(), "0.4124540336401075977833613682588");
77 /// assert_eq!(o, Greater);
78 /// ```
79 pub fn prouhet_thue_morse_constant_prec_round(prec: u64, rm: RoundingMode) -> (Self, Ordering) {
80 assert_ne!(prec, 0);
81 assert_ne!(rm, Exact);
82 // If the result is 1/2 then the exponent is 0 rather than -1, so we handle that case
83 // separately.
84 if prec == 1 && (rm == Nearest || rm == Ceiling || rm == Up) {
85 return (Self::ONE_HALF, Greater);
86 } else if prec == 2 && (rm == Ceiling || rm == Up) {
87 // TODO implement const_from_unsigned_prec_times_power_of_2
88 return (Self::one_half_prec(2), Greater);
89 }
90 let len = bit_to_limb_count_ceiling(prec);
91 let mut limbs = vec![0; len];
92 let mut tms = thue_morse_sequence();
93 for (i, b) in (0..len).rev().zip(&mut tms) {
94 limbs[i] = if b {
95 limbs[i + 1] |= 1;
96 LIMB_1
97 } else {
98 LIMB_0
99 };
100 }
101 let lsb = Limb::power_of_2(prec.neg_mod_power_of_2(Limb::LOG_WIDTH));
102 let mut next_tms = false;
103 if lsb == 1 {
104 next_tms = tms.next().unwrap();
105 if next_tms {
106 limbs[0] |= 1;
107 }
108 }
109 let increment = match rm {
110 Up | Ceiling => true,
111 Down | Floor => false,
112 Nearest => match lsb {
113 1 => !next_tms,
114 2 => tms.next().unwrap(),
115 _ => limbs[0] & (lsb >> 1) != 0,
116 },
117 Exact => unreachable!(),
118 };
119 limbs[0] &= !(lsb - 1);
120 let mut significand = Natural::from_owned_limbs_asc(limbs);
121 if increment {
122 significand += Natural::from(lsb);
123 }
124 (
125 Self(Finite {
126 sign: true,
127 exponent: -1,
128 precision: prec,
129 significand,
130 }),
131 if increment { Greater } else { Less },
132 )
133 }
134
135 /// Returns an approximation of the Prouhet-Thue-Morse constant, with the given precision and
136 /// rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also returned,
137 /// indicating whether the rounded value is less than or greater than the exact value of the
138 /// constant. (Since the constant is irrational, the rounded value is never equal to the exact
139 /// value.)
140 ///
141 /// The Prouhet-Thue-Morse constant is the real number whose bits are the Thue-Morse sequence.
142 /// That is,
143 /// $$
144 /// \tau = \sum_{k=0}^\infty\frac{t_n}{2^{n+1}}+\varepsilon,
145 /// $$
146 /// where $t_n$ is the Thue-Morse sequence.
147 /// - $|\varepsilon| < 2^{-p-2}$.
148 ///
149 /// An alternative expression, from <https://mathworld.wolfram.com/Thue-MorseConstant.html>, is
150 /// $$
151 /// \tau = \frac{1}{4}\left[2-\prod_{k=0}^\infty\left(1-\frac{1}{2^{2^k}}\right)\right].
152 /// $$
153 ///
154 /// The constant is irrational and transcendental.
155 ///
156 /// The output has precision `prec`.
157 ///
158 /// # Worst-case complexity
159 /// $T(n) = O(n)$
160 ///
161 /// $M(n) = O(n)$
162 ///
163 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
164 ///
165 /// # Panics
166 /// Panics if `prec` is zero.
167 ///
168 /// # Examples
169 /// ```
170 /// use malachite_float::Float;
171 /// use std::cmp::Ordering::*;
172 ///
173 /// let (tmc, o) = Float::prouhet_thue_morse_constant_prec(1);
174 /// assert_eq!(tmc.to_string(), "0.5");
175 /// assert_eq!(o, Greater);
176 ///
177 /// let (tmc, o) = Float::prouhet_thue_morse_constant_prec(10);
178 /// assert_eq!(tmc.to_string(), "0.4126");
179 /// assert_eq!(o, Greater);
180 ///
181 /// let (tmc, o) = Float::prouhet_thue_morse_constant_prec(100);
182 /// assert_eq!(tmc.to_string(), "0.4124540336401075977833613682584");
183 /// assert_eq!(o, Less);
184 /// ```
185 #[inline]
186 pub fn prouhet_thue_morse_constant_prec(prec: u64) -> (Self, Ordering) {
187 Self::prouhet_thue_morse_constant_prec_round(prec, Nearest)
188 }
189}