probability_rs/dist/
exponential.rs1use crate::dist::{Continuous, DistError, Distribution, Moments};
2use crate::rng::RngCore;
3
4#[derive(Debug, Clone, Copy)]
5pub struct Exponential {
6 lambda: f64,
7}
8
9impl Exponential {
10 pub fn new(lambda: f64) -> Result<Self, DistError> {
11 if !(lambda > 0.0 && lambda.is_finite()) {
12 return Err(DistError::InvalidParameter);
13 }
14 Ok(Self { lambda })
15 }
16 #[inline]
17 pub fn lambda(&self) -> f64 {
18 self.lambda
19 }
20}
21
22impl Distribution for Exponential {
23 type Value = f64;
24 fn cdf(&self, x: f64) -> f64 {
25 if x <= 0.0 {
26 0.0
27 } else {
28 1.0 - (-self.lambda * x).exp()
29 }
30 }
31 fn in_support(&self, x: f64) -> bool {
32 x >= 0.0 && x.is_finite()
33 }
34 fn sample<R: RngCore>(&self, rng: &mut R) -> f64 {
35 let u = rng.next_f64();
36 -u.ln() / self.lambda
37 }
38}
39
40impl Continuous for Exponential {
41 fn pdf(&self, x: f64) -> f64 {
42 if self.in_support(x) {
43 self.lambda * (-self.lambda * x).exp()
44 } else {
45 0.0
46 }
47 }
48 fn inv_cdf(&self, p: f64) -> f64 {
49 debug_assert!(p > 0.0 && p < 1.0);
50 -(1.0 - p).ln() / self.lambda
51 }
52}
53
54impl Moments for Exponential {
55 fn mean(&self) -> f64 {
56 1.0 / self.lambda
57 }
58 fn variance(&self) -> f64 {
59 1.0 / (self.lambda * self.lambda)
60 }
61 fn skewness(&self) -> f64 { 2.0 }
62 fn kurtosis(&self) -> f64 { 6.0 }
63 fn entropy(&self) -> f64 { 1.0 - self.lambda.ln() }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69 #[test]
70 fn basic_values() {
71 let e = Exponential::new(2.0).unwrap();
72 assert!((e.mean() - 0.5).abs() < 1e-15);
73 assert!((e.variance() - 0.25).abs() < 1e-15);
74 assert!((e.cdf(0.0) - 0.0).abs() < 1e-15);
75 assert!((e.pdf(0.0) - 2.0).abs() < 1e-12);
76 assert!((e.skewness() - 2.0).abs() < 1e-15);
77 assert!((e.kurtosis() - 6.0).abs() < 1e-15);
78 }
79}