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