1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT 2 // file at the top-level directory of this distribution and at 3 // http://rust-lang.org/COPYRIGHT. 4 // 5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 8 // option. This file may not be copied, modified, or distributed 9 // except according to those terms. 10 11 //! The exponential distribution. 12 13 use {Rng, Rand}; 14 use distributions::{ziggurat, ziggurat_tables, Sample, IndependentSample}; 15 16 /// A wrapper around an `f64` to generate Exp(1) random numbers. 17 /// 18 /// See `Exp` for the general exponential distribution. 19 /// 20 /// Implemented via the ZIGNOR variant[1] of the Ziggurat method. The 21 /// exact description in the paper was adjusted to use tables for the 22 /// exponential distribution rather than normal. 23 /// 24 /// [1]: Jurgen A. Doornik (2005). [*An Improved Ziggurat Method to 25 /// Generate Normal Random 26 /// Samples*](http://www.doornik.com/research/ziggurat.pdf). Nuffield 27 /// College, Oxford 28 /// 29 /// # Example 30 /// 31 /// ```rust 32 /// use rand::distributions::exponential::Exp1; 33 /// 34 /// let Exp1(x) = rand::random(); 35 /// println!("{}", x); 36 /// ``` 37 #[derive(Clone, Copy, Debug)] 38 pub struct Exp1(pub f64); 39 40 // This could be done via `-rng.gen::<f64>().ln()` but that is slower. 41 impl Rand for Exp1 { 42 #[inline] rand<R:Rng>(rng: &mut R) -> Exp143 fn rand<R:Rng>(rng: &mut R) -> Exp1 { 44 #[inline] 45 fn pdf(x: f64) -> f64 { 46 (-x).exp() 47 } 48 #[inline] 49 fn zero_case<R:Rng>(rng: &mut R, _u: f64) -> f64 { 50 ziggurat_tables::ZIG_EXP_R - rng.gen::<f64>().ln() 51 } 52 53 Exp1(ziggurat(rng, false, 54 &ziggurat_tables::ZIG_EXP_X, 55 &ziggurat_tables::ZIG_EXP_F, 56 pdf, zero_case)) 57 } 58 } 59 60 /// The exponential distribution `Exp(lambda)`. 61 /// 62 /// This distribution has density function: `f(x) = lambda * 63 /// exp(-lambda * x)` for `x > 0`. 64 /// 65 /// # Example 66 /// 67 /// ```rust 68 /// use rand::distributions::{Exp, IndependentSample}; 69 /// 70 /// let exp = Exp::new(2.0); 71 /// let v = exp.ind_sample(&mut rand::thread_rng()); 72 /// println!("{} is from a Exp(2) distribution", v); 73 /// ``` 74 #[derive(Clone, Copy, Debug)] 75 pub struct Exp { 76 /// `lambda` stored as `1/lambda`, since this is what we scale by. 77 lambda_inverse: f64 78 } 79 80 impl Exp { 81 /// Construct a new `Exp` with the given shape parameter 82 /// `lambda`. Panics if `lambda <= 0`. 83 #[inline] new(lambda: f64) -> Exp84 pub fn new(lambda: f64) -> Exp { 85 assert!(lambda > 0.0, "Exp::new called with `lambda` <= 0"); 86 Exp { lambda_inverse: 1.0 / lambda } 87 } 88 } 89 90 impl Sample<f64> for Exp { sample<R: Rng>(&mut self, rng: &mut R) -> f6491 fn sample<R: Rng>(&mut self, rng: &mut R) -> f64 { self.ind_sample(rng) } 92 } 93 impl IndependentSample<f64> for Exp { ind_sample<R: Rng>(&self, rng: &mut R) -> f6494 fn ind_sample<R: Rng>(&self, rng: &mut R) -> f64 { 95 let Exp1(n) = rng.gen::<Exp1>(); 96 n * self.lambda_inverse 97 } 98 } 99 100 #[cfg(test)] 101 mod test { 102 use distributions::{Sample, IndependentSample}; 103 use super::Exp; 104 105 #[test] test_exp()106 fn test_exp() { 107 let mut exp = Exp::new(10.0); 108 let mut rng = ::test::rng(); 109 for _ in 0..1000 { 110 assert!(exp.sample(&mut rng) >= 0.0); 111 assert!(exp.ind_sample(&mut rng) >= 0.0); 112 } 113 } 114 #[test] 115 #[should_panic] test_exp_invalid_lambda_zero()116 fn test_exp_invalid_lambda_zero() { 117 Exp::new(0.0); 118 } 119 #[test] 120 #[should_panic] test_exp_invalid_lambda_neg()121 fn test_exp_invalid_lambda_neg() { 122 Exp::new(-10.0); 123 } 124 } 125