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, floor_and_ceiling};
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)$
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.83462684167407318628142973279898"
60 /// );
61 /// assert_eq!(o, Less);
62 ///
63 /// let (gauss_constant, o) = Float::gauss_constant_prec_round(100, Ceiling);
64 /// assert_eq!(
65 /// gauss_constant.to_string(),
66 /// "0.83462684167407318628142973279977"
67 /// );
68 /// assert_eq!(o, Greater);
69 /// ```
70 pub fn gauss_constant_prec_round(prec: u64, rm: RoundingMode) -> (Self, Ordering) {
71 let mut working_prec = prec + 10;
72 let mut increment = Limb::WIDTH;
73 loop {
74 let (sqrt_2_lo, sqrt_2_hi) =
75 floor_and_ceiling(Self::sqrt_2_prec_round(working_prec, Floor));
76 let lo = Self::ONE
77 .agm_round(sqrt_2_hi, Ceiling)
78 .0
79 .reciprocal_round(Floor)
80 .0;
81 let hi = Self::ONE
82 .agm_round(sqrt_2_lo, Floor)
83 .0
84 .reciprocal_round(Ceiling)
85 .0;
86 let (gauss_constant_lo, mut o_lo) = Self::from_float_prec_round(lo, prec, rm);
87 let (gauss_constant_hi, mut o_hi) = Self::from_float_prec_round(hi, prec, rm);
88 if o_lo == Equal {
89 o_lo = o_hi;
90 }
91 if o_hi == Equal {
92 o_hi = o_lo;
93 }
94 if o_lo == o_hi && gauss_constant_lo == gauss_constant_hi {
95 return (gauss_constant_lo, o_lo);
96 }
97 working_prec += increment;
98 increment = working_prec >> 1;
99 }
100 }
101
102 /// Returns an approximation of Gauss's constant, $G=1/\mathrm{AGM}(1,\sqrt{2})$, with the given
103 /// precision and rounded to the nearest [`Float`] of that precision. An [`Ordering`] is also
104 /// returned, indicating whether the rounded value is less than or greater than the exact value
105 /// of the constant. (Since the constant is irrational, the rounded value is never equal to the
106 /// exact value.)
107 ///
108 /// $$
109 /// x=G+\varepsilon=1/\mathrm{AGM}(1,\sqrt{2})+\varepsilon,
110 /// $$
111 /// where AGM is the arithmetic-geometric mean.
112 /// - $|\varepsilon| < 2^{-p-1}$.
113 ///
114 /// The constant is irrational and transcendental.
115 ///
116 /// The output has precision `prec`.
117 ///
118 /// # Worst-case complexity
119 /// $T(n) = O(n (\log n)^2 \log\log n)$
120 ///
121 /// $M(n) = O(n \log n)$
122 ///
123 /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
124 ///
125 /// # Panics
126 /// Panics if `prec` is zero.
127 ///
128 /// # Examples
129 /// ```
130 /// use malachite_float::Float;
131 /// use std::cmp::Ordering::*;
132 ///
133 /// let (gauss_constant, o) = Float::gauss_constant_prec(1);
134 /// assert_eq!(gauss_constant.to_string(), "1.0");
135 /// assert_eq!(o, Greater);
136 ///
137 /// let (gauss_constant, o) = Float::gauss_constant_prec(10);
138 /// assert_eq!(gauss_constant.to_string(), "0.83496");
139 /// assert_eq!(o, Greater);
140 ///
141 /// let (gauss_constant, o) = Float::gauss_constant_prec(100);
142 /// assert_eq!(
143 /// gauss_constant.to_string(),
144 /// "0.83462684167407318628142973279898"
145 /// );
146 /// assert_eq!(o, Less);
147 /// ```
148 #[inline]
149 pub fn gauss_constant_prec(prec: u64) -> (Self, Ordering) {
150 Self::gauss_constant_prec_round(prec, Nearest)
151 }
152}