malachite_float/constants/gauss_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 core::cmp::Ordering::*;
18use malachite_base::num::basic::integers::PrimitiveInt;
19use malachite_base::num::basic::traits::One;
20use malachite_base::rounding_modes::RoundingMode::{self, *};
21use malachite_nz::platform::Limb;
22
23impl Float {
24 /// Returns an approximation of Gauss's constant, with the given precision and rounded using the
25 /// given [`RoundingMode`]. An [`Ordering`] is also returned, indicating whether the rounded
26 /// value is less than or greater than the exact value of the constant. (Since the constant is
27 /// irrational, the rounded value is never equal to the exact value.)
28 ///
29 /// $$
30 /// x = G+\varepsilon=1/\mathrm{AGM}(1,\sqrt{2})+\varepsilon,
31 /// $$
32 /// where AGM is the arithmetic-geometric mean.
33 /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{-p}$.
34 /// - If $m$ is `Nearest`, then $|\varepsilon| < 2^{-p-1}$.
35 ///
36 /// The constant is irrational and transcendental.
37 ///
38 /// The output has precision `prec`.
39 ///
40 /// # Worst-case complexity
41 /// $T(n) = O(n (\log n)^2 \log\log n)$
42 ///
43 /// $M(n) = O(n (\log n)^2)$
44 ///
45 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
46 ///
47 /// # Panics
48 /// Panics if `prec` is zero or if `rm` is `Exact`.
49 ///
50 /// # Examples
51 /// ```
52 /// use malachite_base::rounding_modes::RoundingMode::*;
53 /// use malachite_float::Float;
54 /// use std::cmp::Ordering::*;
55 ///
56 /// let (gauss_constant, o) = Float::gauss_constant_prec_round(100, Floor);
57 /// assert_eq!(
58 /// gauss_constant.to_string(),
59 /// "0.834626841674073186281429732799"
60 /// );
61 /// assert_eq!(o, Less);
62 ///
63 /// let (gauss_constant, o) = Float::gauss_constant_prec_round(100, Ceiling);
64 /// assert_eq!(gauss_constant.to_string(), "0.8346268416740731862814297328");
65 /// assert_eq!(o, Greater);
66 /// ```
67 pub fn gauss_constant_prec_round(prec: u64, rm: RoundingMode) -> (Self, Ordering) {
68 let mut working_prec = prec + 10;
69 let mut increment = Limb::WIDTH;
70 loop {
71 let sqrt_2_lo = Self::sqrt_2_prec_round(working_prec, Floor).0;
72 let mut sqrt_2_hi = sqrt_2_lo.clone();
73 sqrt_2_hi.increment();
74 let lo = Self::ONE
75 .agm_round(sqrt_2_hi, Ceiling)
76 .0
77 .reciprocal_round(Floor)
78 .0;
79 let hi = Self::ONE
80 .agm_round(sqrt_2_lo, Floor)
81 .0
82 .reciprocal_round(Ceiling)
83 .0;
84 let (gauss_constant_lo, mut o_lo) = Self::from_float_prec_round(lo, prec, rm);
85 let (gauss_constant_hi, mut o_hi) = Self::from_float_prec_round(hi, prec, rm);
86 if o_lo == Equal {
87 o_lo = o_hi;
88 }
89 if o_hi == Equal {
90 o_hi = o_lo;
91 }
92 if o_lo == o_hi && gauss_constant_lo == gauss_constant_hi {
93 return (gauss_constant_lo, o_lo);
94 }
95 working_prec += increment;
96 increment = working_prec >> 1;
97 }
98 }
99
100 /// Returns an approximation of Gauss's constant, $G=1/\mathrm{AGM}(1,\sqrt{2})$, with the given
101 /// precision and rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also
102 /// returned, indicating whether the rounded value is less than or greater than the exact value
103 /// of the constant. (Since the constant is irrational, the rounded value is never equal to the
104 /// exact value.)
105 ///
106 /// $$
107 /// x=G+\varepsilon=1/\mathrm{AGM}(1,\sqrt{2})+\varepsilon,
108 /// $$
109 /// where AGM is the arithmetic-geometric mean.
110 /// - $|\varepsilon| < 2^{-p-1}$.
111 ///
112 /// The constant is irrational and transcendental.
113 ///
114 /// The output has precision `prec`.
115 ///
116 /// # Worst-case complexity
117 /// $T(n) = O(n (\log n)^2 \log\log n)$
118 ///
119 /// $M(n) = O(n (\log n)^2)$
120 ///
121 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
122 ///
123 /// # Panics
124 /// Panics if `prec` is zero.
125 ///
126 /// # Examples
127 /// ```
128 /// use malachite_float::Float;
129 /// use std::cmp::Ordering::*;
130 ///
131 /// let (gauss_constant, o) = Float::gauss_constant_prec(1);
132 /// assert_eq!(gauss_constant.to_string(), "1.0");
133 /// assert_eq!(o, Greater);
134 ///
135 /// let (gauss_constant, o) = Float::gauss_constant_prec(10);
136 /// assert_eq!(gauss_constant.to_string(), "0.835");
137 /// assert_eq!(o, Greater);
138 ///
139 /// let (gauss_constant, o) = Float::gauss_constant_prec(100);
140 /// assert_eq!(
141 /// gauss_constant.to_string(),
142 /// "0.834626841674073186281429732799"
143 /// );
144 /// assert_eq!(o, Less);
145 /// ```
146 #[inline]
147 pub fn gauss_constant_prec(prec: u64) -> (Self, Ordering) {
148 Self::gauss_constant_prec_round(prec, Nearest)
149 }
150}