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