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