statrs/function/
exponential.rs1use crate::{consts, Result, StatsError};
4
5pub fn integral(x: f64, n: u64) -> Result<f64> {
38 let eps = 0.00000000000000001;
39 let max_iter = 100;
40 let nf64 = n as f64;
41 let near_f64min = 1e-100; if n == 0 {
45 return Ok((-1.0 * x).exp() / x);
46 }
47 if x == 0.0 {
48 return Ok(1.0 / (nf64 - 1.0));
49 }
50
51 if x > 1.0 {
52 let mut b = x + nf64;
53 let mut c = 1.0 / near_f64min;
54 let mut d = 1.0 / b;
55 let mut h = d;
56 for i in 1..max_iter + 1 {
57 let a = -1.0 * i as f64 * (nf64 - 1.0 + i as f64);
58 b += 2.0;
59 d = 1.0 / (a * d + b);
60 c = b + a / c;
61 let del = c * d;
62 h *= del;
63 if (del - 1.0).abs() < eps {
64 return Ok(h * (-x).exp());
65 }
66 }
67 Err(StatsError::ComputationFailedToConverge)
68 } else {
69 let mut factorial = 1.0;
70 let mut result = if n - 1 != 0 {
71 1.0 / (nf64 - 1.0)
72 } else {
73 -1.0 * x.ln() - consts::EULER_MASCHERONI
74 };
75 for i in 1..max_iter + 1 {
76 factorial *= -1.0 * x / i as f64;
77 let del = if i != n - 1 {
78 -factorial / (i as f64 - nf64 + 1.0)
79 } else {
80 let mut psi = -1.0 * consts::EULER_MASCHERONI;
81 for ii in 1..n {
82 psi += 1.0 / ii as f64;
83 }
84 factorial * (-1.0 * x.ln() + psi)
85 };
86 result += del;
87 if del.abs() < result.abs() * eps {
88 return Ok(result);
89 }
90 }
91 Err(StatsError::ComputationFailedToConverge)
92 }
93}
94
95#[rustfmt::skip]
96#[cfg(test)]
97mod tests {
98 #[test]
99 fn test_integral() {
100 assert_eq!(super::integral(0.001, 1).unwrap(), 6.33153936413614904);
101 assert_almost_eq!(super::integral(0.1, 1).unwrap(), 1.82292395841939059, 1e-15);
102 assert_eq!(super::integral(1.0, 1).unwrap(), 0.219383934395520286);
103 assert_almost_eq!(super::integral(2.0, 1).unwrap(), 0.0489005107080611248, 1e-15);
104 assert_almost_eq!(super::integral(2.5, 1).unwrap(), 0.0249149178702697399, 1e-15);
105 assert_almost_eq!(super::integral(10.0, 1).unwrap(), 4.15696892968532464e-06, 1e-20);
106 assert_eq!(super::integral(0.001, 2).unwrap(), 0.992668960469238915);
107 assert_almost_eq!(super::integral(0.1, 2).unwrap(), 0.722545022194020392, 1e-15);
108 assert_almost_eq!(super::integral(1.0, 2).unwrap(), 0.148495506775922048, 1e-16);
109 assert_almost_eq!(super::integral(2.0, 2).unwrap(), 0.0375342618204904527, 1e-16);
110 assert_almost_eq!(super::integral(10.0, 2).unwrap(), 3.830240465631608e-06, 1e-20);
111 assert_eq!(super::integral(0.001, 0).unwrap(), 999.000499833375);
112 assert_eq!(super::integral(0.1, 0).unwrap(), 9.048374180359595);
113 assert_almost_eq!(super::integral(1.0, 0).unwrap(), 0.3678794411714423, 1e-16);
114 assert_eq!(super::integral(2.0, 0).unwrap(), 0.06766764161830635);
115 assert_eq!(super::integral(10.0, 0).unwrap(), 4.539992976248485e-06);
116 }
117}