malachite_float/constants/lemniscate_constant.rs
1// Copyright © 2026 Mikhail Hogrefe
2//
3// Uses code adopted from the GNU MPFR Library.
4//
5// Copyright 1999, 2001-2024 Free Software Foundation, Inc.
6//
7// Contributed by the AriC and Caramba projects, INRIA.
8//
9// This file is part of Malachite.
10//
11// Malachite is free software: you can redistribute it and/or modify it under the terms of the GNU
12// Lesser General Public License (LGPL) as published by the Free Software Foundation; either version
13// 3 of the License, or (at your option) any later version. See <https://www.gnu.org/licenses/>.
14
15use crate::Float;
16use core::cmp::Ordering;
17use malachite_base::num::basic::integers::PrimitiveInt;
18use malachite_base::rounding_modes::RoundingMode::{self, *};
19use malachite_nz::natural::arithmetic::float_extras::float_can_round;
20use malachite_nz::platform::Limb;
21
22impl Float {
23 /// Returns an approximation of the lemniscate constant $\varpi$, with the given precision and
24 /// rounded using the given [`RoundingMode`]. An [`Ordering`] is also returned, indicating
25 /// whether the rounded value is less than or greater than the exact value of the constant.
26 /// (Since the constant is irrational, the rounded value is never equal to the exact value.)
27 ///
28 /// $$
29 /// x = \varpi+\varepsilon=\pi G+\varepsilon,
30 /// $$
31 /// where $G$ is Gauss's constant.
32 /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{-p+2}$.
33 /// - If $m$ is `Nearest`, then $|\varepsilon| < 2^{-p+1}$.
34 ///
35 /// The constant is irrational and transcendental.
36 ///
37 /// The output has precision `prec`.
38 ///
39 /// # Worst-case complexity
40 /// $T(n) = O(n (\log n)^2 \log\log n)$
41 ///
42 /// $M(n) = O(n (\log n)^2)$
43 ///
44 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
45 ///
46 /// # Panics
47 /// Panics if `prec` is zero or if `rm` is `Exact`.
48 ///
49 /// # Examples
50 /// ```
51 /// use malachite_base::rounding_modes::RoundingMode::*;
52 /// use malachite_float::Float;
53 /// use std::cmp::Ordering::*;
54 ///
55 /// let (lemniscate_constant, o) = Float::lemniscate_constant_prec_round(100, Floor);
56 /// assert_eq!(
57 /// lemniscate_constant.to_string(),
58 /// "2.62205755429211981046483958989"
59 /// );
60 /// assert_eq!(o, Less);
61 ///
62 /// let (lemniscate_constant, o) = Float::lemniscate_constant_prec_round(100, Ceiling);
63 /// assert_eq!(
64 /// lemniscate_constant.to_string(),
65 /// "2.622057554292119810464839589893"
66 /// );
67 /// assert_eq!(o, Greater);
68 /// ```
69 pub fn lemniscate_constant_prec_round(prec: u64, rm: RoundingMode) -> (Self, Ordering) {
70 let mut working_prec = prec + 10;
71 let mut increment = Limb::WIDTH;
72 loop {
73 let lemniscate_constant =
74 Self::pi_prec(working_prec).0 * Self::gauss_constant_prec(working_prec).0;
75 if float_can_round(
76 lemniscate_constant.significand_ref().unwrap(),
77 working_prec - 2,
78 prec,
79 rm,
80 ) {
81 return Self::from_float_prec_round(lemniscate_constant, prec, rm);
82 }
83 working_prec += increment;
84 increment = working_prec >> 1;
85 }
86 }
87
88 /// Returns an approximation of the lemniscate constant $\varpi$, with the given precision and
89 /// rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also returned,
90 /// indicating whether the rounded value is less than or greater than the exact value of the
91 /// constant. (Since the constant is irrational, the rounded value is never equal to the exact
92 /// value.)
93 ///
94 /// $$
95 /// x = \varpi+\varepsilon=\pi G+\varepsilon,
96 /// $$
97 /// where $G$ is Gauss's constant.
98 /// - $|\varepsilon| < 2^{-p+1}$.
99 ///
100 /// The constant is irrational and transcendental.
101 ///
102 /// The output has precision `prec`.
103 ///
104 /// # Worst-case complexity
105 /// $T(n) = O(n (\log n)^2 \log\log n)$
106 ///
107 /// $M(n) = O(n (\log n)^2)$
108 ///
109 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
110 ///
111 /// # Panics
112 /// Panics if `prec` is zero.
113 ///
114 /// # Examples
115 /// ```
116 /// use malachite_float::Float;
117 /// use std::cmp::Ordering::*;
118 ///
119 /// let (lemniscate_constant, o) = Float::lemniscate_constant_prec(1);
120 /// assert_eq!(lemniscate_constant.to_string(), "2.0");
121 /// assert_eq!(o, Less);
122 ///
123 /// let (lemniscate_constant, o) = Float::lemniscate_constant_prec(10);
124 /// assert_eq!(lemniscate_constant.to_string(), "2.621");
125 /// assert_eq!(o, Less);
126 ///
127 /// let (lemniscate_constant, o) = Float::lemniscate_constant_prec(100);
128 /// assert_eq!(
129 /// lemniscate_constant.to_string(),
130 /// "2.62205755429211981046483958989"
131 /// );
132 /// assert_eq!(o, Less);
133 /// ```
134 #[inline]
135 pub fn lemniscate_constant_prec(prec: u64) -> (Self, Ordering) {
136 Self::lemniscate_constant_prec_round(prec, Nearest)
137 }
138}