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}