1#![doc = include_str!("../README.md")]
2
3use rug::{Float, ops::Pow};
4use std::convert::TryFrom;
5
6pub fn compute_pi(digits: usize) -> Float {
20 let precision = ((digits as f64) * 3.3219280948874).ceil() as u32 + 10;
21 let threshold = Float::with_val(precision, 10).pow(-i32::try_from(digits).unwrap());
22 let mut a = Float::with_val(precision, 1);
23 let two = Float::with_val(precision, 2);
24 let mut b = Float::with_val(precision, 1.0 / two.sqrt());
25 let mut t = Float::with_val(precision, 0.25);
26 let mut p = Float::with_val(precision, 1);
27 let mut pi_old = Float::with_val(precision, 0);
28
29 let pi_result = loop {
30 let sum = a.clone() + b.clone();
31 let a_next = Float::with_val(precision, &sum / 2.0);
32 let product = Float::with_val(precision, &a * &b);
33 b = product.sqrt();
34 let difference = Float::with_val(precision, &a - &a_next);
35 let difference_squared = difference.pow(2);
36 t -= &p * difference_squared;
37 a = a_next;
38 p *= 2;
39 let denominator = Float::with_val(precision, &t * 4.0);
40 let numerator = Float::with_val(precision, (&sum).pow(2));
41 let pi = numerator / denominator;
42 let pi_diff = Float::with_val(pi.prec(), &pi - &pi_old).abs();
43 if pi_diff < threshold {
44 break pi;
45 }
46 pi_old = pi;
47 };
48 pi_result
49}
50
51pub fn compute_pi_str(digits: usize) -> String {
65 let pi = compute_pi(digits);
66 let pi_str = pi.to_string_radix(10, Some(digits + 5));
67 let pi_str_trimmed = pi_str[0..(digits + 2)].to_string();
68 pi_str_trimmed
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74
75 #[test]
76 fn test_compute_pi_10_digits() {
77 let pi_computed = compute_pi(10);
78 let pi_expected = Float::with_val(256, 3.1415926535);
79 assert!((pi_computed - &pi_expected).abs() < Float::with_val(256, 1e-10));
80 }
81
82 #[test]
83 fn test_compute_pi_str() {
84 let pi_str_5 = compute_pi_str(5);
86 assert_eq!(pi_str_5, "3.14159");
87
88 let pi_str_10 = compute_pi_str(10);
90 assert_eq!(pi_str_10, "3.1415926535");
91 }
92}