Skip to main content

malachite_float/constants/
sqrt_pi.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::arithmetic::traits::Sqrt;
18use malachite_base::num::basic::integers::PrimitiveInt;
19use malachite_base::rounding_modes::RoundingMode::{self, *};
20use malachite_nz::natural::arithmetic::float_extras::float_can_round;
21use malachite_nz::platform::Limb;
22
23impl Float {
24    /// Returns an approximation of $\sqrt{\pi}$, 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 = \sqrt{\pi}+\varepsilon.
31    /// $$
32    /// - If $m$ is not `Nearest`, then $|\varepsilon| < 2^{-p+1}$.
33    /// - If $m$ is `Nearest`, then $|\varepsilon| < 2^{-p}$.
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 (sqrt_pi, o) = Float::sqrt_pi_prec_round(100, Floor);
56    /// assert_eq!(sqrt_pi.to_string(), "1.77245385090551602729816748334");
57    /// assert_eq!(o, Less);
58    ///
59    /// let (sqrt_pi, o) = Float::sqrt_pi_prec_round(100, Ceiling);
60    /// assert_eq!(sqrt_pi.to_string(), "1.772453850905516027298167483341");
61    /// assert_eq!(o, Greater);
62    /// ```
63    pub fn sqrt_pi_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 sqrt_pi = Self::pi_prec_round(working_prec, Floor).0.sqrt();
68            // See algorithms.tex. Since we rounded down when computing pi, the absolute error of
69            // the square root is bounded by (c_sqrt + k_fx)ulp(sqrt) <= 2ulp(sqrt).
70            if float_can_round(
71                sqrt_pi.significand_ref().unwrap(),
72                working_prec - 1,
73                prec,
74                rm,
75            ) {
76                return Self::from_float_prec_round(sqrt_pi, prec, rm);
77            }
78            working_prec += increment;
79            increment = working_prec >> 1;
80        }
81    }
82
83    /// Returns an approximation of $\sqrt{\pi}$, with the given precision and rounded to the
84    /// nearest [`Float`] of that precision. An [`Ordering`] is also returned, indicating whether
85    /// the rounded value is less than or greater than the exact value of the constant. (Since the
86    /// constant is irrational, the rounded value is never equal to the exact value.)
87    ///
88    /// $$
89    /// x = \sqrt{\pi}+\varepsilon.
90    /// $$
91    /// - $|\varepsilon| < 2^{-p}$.
92    ///
93    /// The constant is irrational and transcendental.
94    ///
95    /// The output has precision `prec`.
96    ///
97    /// # Worst-case complexity
98    /// $T(n) = O(n (\log n)^2 \log\log n)$
99    ///
100    /// $M(n) = O(n (\log n)^2)$
101    ///
102    /// where $T$ is time, $M$ is additional memory, and $n$ is `prec`.
103    ///
104    /// # Panics
105    /// Panics if `prec` is zero.
106    ///
107    /// # Examples
108    /// ```
109    /// use malachite_float::Float;
110    /// use std::cmp::Ordering::*;
111    ///
112    /// let (sqrt_pi, o) = Float::sqrt_pi_prec(1);
113    /// assert_eq!(sqrt_pi.to_string(), "2.0");
114    /// assert_eq!(o, Greater);
115    ///
116    /// let (sqrt_pi, o) = Float::sqrt_pi_prec(10);
117    /// assert_eq!(sqrt_pi.to_string(), "1.771");
118    /// assert_eq!(o, Less);
119    ///
120    /// let (sqrt_pi, o) = Float::sqrt_pi_prec(100);
121    /// assert_eq!(sqrt_pi.to_string(), "1.772453850905516027298167483341");
122    /// assert_eq!(o, Greater);
123    /// ```
124    #[inline]
125    pub fn sqrt_pi_prec(prec: u64) -> (Self, Ordering) {
126        Self::sqrt_pi_prec_round(prec, Nearest)
127    }
128}