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