1#![doc = include_str!("../README.md")]
2
3use rug::{Float, ops::Pow};
4use std::{convert::TryFrom, f64::consts::LOG2_10};
5
6pub fn compute_tau(digits: usize) -> Float {
20 let precision = ((digits as f64) * (LOG2_10 + 1e-11)).ceil() as u32 + 10 + 1;
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, two.sqrt() / 2);
25 let mut t = Float::with_val(precision, 0.25);
26 let mut p = Float::with_val(precision, 1);
27 let mut tau_old = Float::with_val(precision, 0);
28
29 loop {
30 let sum = a.clone() + &b;
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 * 2.0);
40 let numerator = Float::with_val(precision, (&sum).pow(2));
41 let tau: Float = numerator / denominator;
42 let tau_diff = Float::with_val(tau.prec(), &tau - &tau_old).abs();
43 if tau_diff < threshold {
44 break tau;
45 }
46 tau_old = tau;
47 }
48}
49
50pub fn compute_tau_str(digits: usize) -> String {
64 let tau = compute_tau(digits);
65 let tau_str = tau.to_string_radix(10, Some(digits + 5));
66 tau_str[0..(digits + 2)].to_string()
67}
68
69#[cfg(test)]
70mod tests {
71 use super::*;
72
73 #[test]
74 fn test_compute_tau_10_digits() {
75 let tau_computed = compute_tau(10);
76 let tau_expected = Float::with_val(256, 6.2831853071);
77 assert!((tau_computed - &tau_expected).abs() < Float::with_val(256, 1e-10));
78 }
79
80 #[test]
81 fn test_compute_tau_str() {
82 let tau_str_5 = compute_tau_str(5);
84 assert_eq!(tau_str_5, "6.28318");
85
86 let tau_str_10 = compute_tau_str(10);
88 assert_eq!(tau_str_10, "6.2831853071");
89 }
90}