1 // Copyright 2018 Developers of the Rand project.
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 //! The triangular distribution.
9 
10 use Rng;
11 use distributions::{Distribution, Standard};
12 
13 /// The triangular distribution.
14 ///
15 /// # Example
16 ///
17 /// ```rust
18 /// use rand::distributions::{Triangular, Distribution};
19 ///
20 /// let d = Triangular::new(0., 5., 2.5);
21 /// let v = d.sample(&mut rand::thread_rng());
22 /// println!("{} is from a triangular distribution", v);
23 /// ```
24 #[derive(Clone, Copy, Debug)]
25 pub struct Triangular {
26     min: f64,
27     max: f64,
28     mode: f64,
29 }
30 
31 impl Triangular {
32     /// Construct a new `Triangular` with minimum `min`, maximum `max` and mode
33     /// `mode`.
34     ///
35     /// # Panics
36     ///
37     /// If `max < mode`, `mode < max` or `max == min`.
38     ///
39     #[inline]
new(min: f64, max: f64, mode: f64) -> Triangular40     pub fn new(min: f64, max: f64, mode: f64) -> Triangular {
41         assert!(max >= mode);
42         assert!(mode >= min);
43         assert!(max != min);
44         Triangular { min, max, mode }
45     }
46 }
47 
48 impl Distribution<f64> for Triangular {
49     #[inline]
sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f6450     fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
51         let f: f64 = rng.sample(Standard);
52         let diff_mode_min = self.mode - self.min;
53         let diff_max_min = self.max - self.min;
54         if f * diff_max_min < diff_mode_min {
55             self.min + (f * diff_max_min * diff_mode_min).sqrt()
56         } else {
57             self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt()
58         }
59     }
60 }
61 
62 #[cfg(test)]
63 mod test {
64     use distributions::Distribution;
65     use super::Triangular;
66 
67     #[test]
test_new()68     fn test_new() {
69         for &(min, max, mode) in &[
70             (-1., 1., 0.), (1., 2., 1.), (5., 25., 25.), (1e-5, 1e5, 1e-3),
71             (0., 1., 0.9), (-4., -0.5, -2.), (-13.039, 8.41, 1.17),
72         ] {
73             println!("{} {} {}", min, max, mode);
74             let _ = Triangular::new(min, max, mode);
75         }
76     }
77 
78     #[test]
test_sample()79     fn test_sample() {
80         let norm = Triangular::new(0., 1., 0.5);
81         let mut rng = ::test::rng(1);
82         for _ in 0..1000 {
83             norm.sample(&mut rng);
84         }
85     }
86 }
87