aboutsummaryrefslogtreecommitdiff
path: root/rand/src/distributions/triangular.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rand/src/distributions/triangular.rs')
-rw-r--r--rand/src/distributions/triangular.rs86
1 files changed, 86 insertions, 0 deletions
diff --git a/rand/src/distributions/triangular.rs b/rand/src/distributions/triangular.rs
new file mode 100644
index 0000000..a6eef5c
--- /dev/null
+++ b/rand/src/distributions/triangular.rs
@@ -0,0 +1,86 @@
+// Copyright 2018 Developers of the Rand project.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//! The triangular distribution.
+
+use Rng;
+use distributions::{Distribution, Standard};
+
+/// The triangular distribution.
+///
+/// # Example
+///
+/// ```rust
+/// use rand::distributions::{Triangular, Distribution};
+///
+/// let d = Triangular::new(0., 5., 2.5);
+/// let v = d.sample(&mut rand::thread_rng());
+/// println!("{} is from a triangular distribution", v);
+/// ```
+#[derive(Clone, Copy, Debug)]
+pub struct Triangular {
+ min: f64,
+ max: f64,
+ mode: f64,
+}
+
+impl Triangular {
+ /// Construct a new `Triangular` with minimum `min`, maximum `max` and mode
+ /// `mode`.
+ ///
+ /// # Panics
+ ///
+ /// If `max < mode`, `mode < max` or `max == min`.
+ ///
+ #[inline]
+ pub fn new(min: f64, max: f64, mode: f64) -> Triangular {
+ assert!(max >= mode);
+ assert!(mode >= min);
+ assert!(max != min);
+ Triangular { min, max, mode }
+ }
+}
+
+impl Distribution<f64> for Triangular {
+ #[inline]
+ fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
+ let f: f64 = rng.sample(Standard);
+ let diff_mode_min = self.mode - self.min;
+ let diff_max_min = self.max - self.min;
+ if f * diff_max_min < diff_mode_min {
+ self.min + (f * diff_max_min * diff_mode_min).sqrt()
+ } else {
+ self.max - ((1. - f) * diff_max_min * (self.max - self.mode)).sqrt()
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use distributions::Distribution;
+ use super::Triangular;
+
+ #[test]
+ fn test_new() {
+ for &(min, max, mode) in &[
+ (-1., 1., 0.), (1., 2., 1.), (5., 25., 25.), (1e-5, 1e5, 1e-3),
+ (0., 1., 0.9), (-4., -0.5, -2.), (-13.039, 8.41, 1.17),
+ ] {
+ println!("{} {} {}", min, max, mode);
+ let _ = Triangular::new(min, max, mode);
+ }
+ }
+
+ #[test]
+ fn test_sample() {
+ let norm = Triangular::new(0., 1., 0.5);
+ let mut rng = ::test::rng(1);
+ for _ in 0..1000 {
+ norm.sample(&mut rng);
+ }
+ }
+}