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}