Skip to main content

malachite_float/float/constants/
ramanujans_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, floor_and_ceiling};
10use core::cmp::Ordering::{self, *};
11use malachite_base::num::basic::integers::PrimitiveInt;
12use malachite_base::rounding_modes::RoundingMode::{self, *};
13use malachite_nz::platform::Limb;
14
15impl Float {
16    /// Returns an approximation of Ramanujan's constant, $e^{\pi\sqrt{163}}$, with the given
17    /// precision and rounded using the given [`RoundingMode`]. An [`Ordering`] is also returned,
18    /// indicating whether the rounded value is less than or greater than the exact value of the
19    /// constant. (Since the constant is irrational, the rounded value is never equal to the exact
20    /// value.)
21    ///
22    /// $$
23    /// x = e^{\pi\sqrt{163}}+\varepsilon.
24    /// $$
25    /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{-p+58}$.
26    /// - If $m$ is `Nearest`, then $|\varepsilon| < 2^{-p+57}$.
27    ///
28    /// The constant is irrational and transcendental. It is famously close to an integer: $e^{\pi
29    /// \sqrt{163}} \approx 262{,}537{,}412{,}640{,}768{,}744 - 7.5 \times 10^{-13}$.
30    ///
31    /// The output has precision `prec`.
32    ///
33    /// # Worst-case complexity
34    /// $T(n) = O(n^{3/2} \log n \log\log n)$
35    ///
36    /// $M(n) = O(n \log n)$
37    ///
38    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
39    ///
40    /// # Panics
41    /// Panics if `prec` is zero or if `rm` is `Exact`.
42    ///
43    /// # Examples
44    /// ```
45    /// use malachite_base::rounding_modes::RoundingMode::*;
46    /// use malachite_float::Float;
47    /// use std::cmp::Ordering::*;
48    ///
49    /// let (ramanujans_constant, o) = Float::ramanujans_constant_prec_round(100, Floor);
50    /// assert_eq!(
51    ///     ramanujans_constant.to_string(),
52    ///     "262537412640768743.99999999999909"
53    /// );
54    /// assert_eq!(o, Less);
55    ///
56    /// let (ramanujans_constant, o) = Float::ramanujans_constant_prec_round(100, Ceiling);
57    /// assert_eq!(
58    ///     ramanujans_constant.to_string(),
59    ///     "262537412640768743.99999999999932"
60    /// );
61    /// assert_eq!(o, Greater);
62    /// ```
63    pub fn ramanujans_constant_prec_round(prec: u64, rm: RoundingMode) -> (Self, Ordering) {
64        let mut working_prec = prec + 10;
65        let mut increment = Limb::WIDTH;
66        loop {
67            let (pi_lo, pi_hi) = floor_and_ceiling(Self::pi_prec_round(working_prec, Floor));
68            let (sqrt_163_lo, sqrt_163_hi) = floor_and_ceiling(
69                const { Self::const_from_unsigned(163) }.sqrt_prec_round(working_prec, Floor),
70            );
71            // pi and sqrt(163) are positive, so pi * sqrt(163) is bracketed by the products of the
72            // corresponding bounds.
73            //
74            // exp is increasing, so exp(arg_lo) <= exp(pi * sqrt(163)) <= exp(arg_hi).
75            let (ramanujans_constant_lo, mut o_lo) = Self::from_float_prec_round(
76                pi_lo.mul_round(sqrt_163_lo, Floor).0.exp_round(Floor).0,
77                prec,
78                rm,
79            );
80            let (ramanujans_constant_hi, mut o_hi) = Self::from_float_prec_round(
81                pi_hi.mul_round(sqrt_163_hi, Ceiling).0.exp_round(Ceiling).0,
82                prec,
83                rm,
84            );
85            if o_lo == Equal {
86                o_lo = o_hi;
87            }
88            if o_hi == Equal {
89                o_hi = o_lo;
90            }
91            if o_lo == o_hi && ramanujans_constant_lo == ramanujans_constant_hi {
92                return (ramanujans_constant_lo, o_lo);
93            }
94            working_prec += increment;
95            increment = working_prec >> 1;
96        }
97    }
98
99    /// Returns an approximation of Ramanujan's constant, $e^{\pi\sqrt{163}}$, with the given
100    /// precision and rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also
101    /// returned, indicating whether the rounded value is less than or greater than the exact value
102    /// of the constant. (Since the constant is irrational, the rounded value is never equal to the
103    /// exact value.)
104    ///
105    /// $$
106    /// x = e^{\pi\sqrt{163}}+\varepsilon.
107    /// $$
108    /// - $|\varepsilon| < 2^{-p+57}$.
109    ///
110    /// The constant is irrational and transcendental. It is famously close to an integer: $e^{\pi
111    /// \sqrt{163}} \approx 262{,}537{,}412{,}640{,}768{,}744 - 7.5 \times 10^{-13}$.
112    ///
113    /// The output has precision `prec`.
114    ///
115    /// # Worst-case complexity
116    /// $T(n) = O(n^{3/2} \log n \log\log n)$
117    ///
118    /// $M(n) = O(n \log n)$
119    ///
120    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
121    ///
122    /// # Panics
123    /// Panics if `prec` is zero.
124    ///
125    /// # Examples
126    /// ```
127    /// use malachite_float::Float;
128    /// use std::cmp::Ordering::*;
129    ///
130    /// let (ramanujans_constant, o) = Float::ramanujans_constant_prec(1);
131    /// assert_eq!(ramanujans_constant.to_string(), "2.9e17");
132    /// assert_eq!(o, Greater);
133    ///
134    /// let (ramanujans_constant, o) = Float::ramanujans_constant_prec(10);
135    /// assert_eq!(ramanujans_constant.to_string(), "2.6262e17");
136    /// assert_eq!(o, Greater);
137    ///
138    /// let (ramanujans_constant, o) = Float::ramanujans_constant_prec(97);
139    /// assert_eq!(
140    ///     ramanujans_constant.to_string(),
141    ///     "262537412640768744.0000000000000"
142    /// );
143    /// assert_eq!(o, Greater);
144    ///
145    /// let (ramanujans_constant, o) = Float::ramanujans_constant_prec(100);
146    /// assert_eq!(
147    ///     ramanujans_constant.to_string(),
148    ///     "262537412640768743.99999999999932"
149    /// );
150    /// assert_eq!(o, Greater);
151    /// ```
152    #[inline]
153    pub fn ramanujans_constant_prec(prec: u64) -> (Self, Ordering) {
154        Self::ramanujans_constant_prec_round(prec, Nearest)
155    }
156}