stats_claw/distributions/positive/
exponential.rs1use super::super::{Cdf, Moments, Pdf, Quantile, Sample};
21use crate::distributions::ExponentialDistribution;
22use crate::rng::SplitMix64;
23
24impl Pdf for ExponentialDistribution {
25 fn pdf(&self, x: f64) -> f64 {
26 if x < 0.0 {
27 0.0
28 } else {
29 self.rate_parameter * (-self.rate_parameter * x).exp()
30 }
31 }
32}
33
34impl Cdf for ExponentialDistribution {
35 fn cdf(&self, x: f64) -> f64 {
36 if x < 0.0 {
37 0.0
38 } else {
39 (-self.rate_parameter * x).exp().mul_add(-1.0, 1.0)
40 }
41 }
42}
43
44impl Quantile for ExponentialDistribution {
45 fn quantile(&self, p: f64) -> f64 {
46 -(1.0 - p).ln() / self.rate_parameter
47 }
48}
49
50impl Moments for ExponentialDistribution {
51 fn mean(&self) -> Option<f64> {
52 Some(1.0 / self.rate_parameter)
53 }
54 fn variance(&self) -> Option<f64> {
55 Some(1.0 / (self.rate_parameter * self.rate_parameter))
56 }
57}
58
59impl Sample for ExponentialDistribution {
60 fn sample(&self, rng: &mut SplitMix64) -> f64 {
61 self.quantile(rng.next_f64())
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68
69 #[test]
71 fn density_at_origin_is_rate() {
72 let d = ExponentialDistribution {
73 rate_parameter: 2.0,
74 ..Default::default()
75 };
76 assert!((d.pdf(0.0) - 2.0).abs() < 1e-12, "was {}", d.pdf(0.0));
77 }
78
79 #[test]
81 fn mean_is_reciprocal_rate() {
82 let d = ExponentialDistribution {
83 rate_parameter: 4.0,
84 ..Default::default()
85 };
86 assert_eq!(d.mean(), Some(0.25));
87 }
88}