ferray_random/distributions/
exponential.rs1use ferray_core::{Array, FerrayError, Ix1};
4
5use crate::bitgen::BitGenerator;
6use crate::generator::{Generator, generate_vec, vec_to_array1};
7
8pub(crate) fn standard_exponential_single<B: BitGenerator>(bg: &mut B) -> f64 {
10 loop {
11 let u = bg.next_f64();
12 if u > f64::EPSILON {
13 return -u.ln();
14 }
15 }
16}
17
18impl<B: BitGenerator> Generator<B> {
19 pub fn standard_exponential(&mut self, size: usize) -> Result<Array<f64, Ix1>, FerrayError> {
29 if size == 0 {
30 return Err(FerrayError::invalid_value("size must be > 0"));
31 }
32 let data = generate_vec(self, size, standard_exponential_single);
33 vec_to_array1(data)
34 }
35
36 pub fn exponential(&mut self, scale: f64, size: usize) -> Result<Array<f64, Ix1>, FerrayError> {
47 if size == 0 {
48 return Err(FerrayError::invalid_value("size must be > 0"));
49 }
50 if scale <= 0.0 {
51 return Err(FerrayError::invalid_value(format!(
52 "scale must be positive, got {scale}"
53 )));
54 }
55 let data = generate_vec(self, size, |bg| scale * standard_exponential_single(bg));
56 vec_to_array1(data)
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use crate::default_rng_seeded;
63
64 #[test]
65 fn standard_exponential_positive() {
66 let mut rng = default_rng_seeded(42);
67 let arr = rng.standard_exponential(10_000).unwrap();
68 let slice = arr.as_slice().unwrap();
69 for &v in slice {
70 assert!(
71 v > 0.0,
72 "standard_exponential produced non-positive value: {v}"
73 );
74 }
75 }
76
77 #[test]
78 fn standard_exponential_mean_variance() {
79 let mut rng = default_rng_seeded(42);
80 let n = 100_000;
81 let arr = rng.standard_exponential(n).unwrap();
82 let slice = arr.as_slice().unwrap();
83 let mean: f64 = slice.iter().sum::<f64>() / n as f64;
84 let var: f64 = slice.iter().map(|&x| (x - mean).powi(2)).sum::<f64>() / n as f64;
85 let se = (1.0 / n as f64).sqrt();
87 assert!((mean - 1.0).abs() < 3.0 * se, "mean {mean} too far from 1");
88 assert!((var - 1.0).abs() < 0.05, "variance {var} too far from 1");
89 }
90
91 #[test]
92 fn exponential_mean() {
93 let mut rng = default_rng_seeded(42);
94 let n = 100_000;
95 let scale = 3.0;
96 let arr = rng.exponential(scale, n).unwrap();
97 let slice = arr.as_slice().unwrap();
98 let mean: f64 = slice.iter().sum::<f64>() / n as f64;
99 let se = (scale * scale / n as f64).sqrt();
100 assert!(
101 (mean - scale).abs() < 3.0 * se,
102 "mean {mean} too far from {scale}"
103 );
104 }
105
106 #[test]
107 fn exponential_bad_scale() {
108 let mut rng = default_rng_seeded(42);
109 assert!(rng.exponential(0.0, 100).is_err());
110 assert!(rng.exponential(-1.0, 100).is_err());
111 }
112
113 #[test]
114 fn exponential_deterministic() {
115 let mut rng1 = default_rng_seeded(42);
116 let mut rng2 = default_rng_seeded(42);
117 let a = rng1.exponential(2.0, 100).unwrap();
118 let b = rng2.exponential(2.0, 100).unwrap();
119 assert_eq!(a.as_slice().unwrap(), b.as_slice().unwrap());
120 }
121}