]> git.proxmox.com Git - cargo.git/blob - vendor/rand/src/distributions/cauchy.rs
New upstream version 0.37.0
[cargo.git] / vendor / rand / src / distributions / cauchy.rs
1 // Copyright 2018 Developers of the Rand project.
2 // Copyright 2016-2017 The Rust Project Developers.
3 //
4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
7 // option. This file may not be copied, modified, or distributed
8 // except according to those terms.
9
10 //! The Cauchy distribution.
11 #![allow(deprecated)]
12
13 use crate::Rng;
14 use crate::distributions::Distribution;
15 use std::f64::consts::PI;
16
17 /// The Cauchy distribution `Cauchy(median, scale)`.
18 ///
19 /// This distribution has a density function:
20 /// `f(x) = 1 / (pi * scale * (1 + ((x - median) / scale)^2))`
21 #[deprecated(since="0.7.0", note="moved to rand_distr crate")]
22 #[derive(Clone, Copy, Debug)]
23 pub struct Cauchy {
24 median: f64,
25 scale: f64
26 }
27
28 impl Cauchy {
29 /// Construct a new `Cauchy` with the given shape parameters
30 /// `median` the peak location and `scale` the scale factor.
31 /// Panics if `scale <= 0`.
32 pub fn new(median: f64, scale: f64) -> Cauchy {
33 assert!(scale > 0.0, "Cauchy::new called with scale factor <= 0");
34 Cauchy {
35 median,
36 scale
37 }
38 }
39 }
40
41 impl Distribution<f64> for Cauchy {
42 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> f64 {
43 // sample from [0, 1)
44 let x = rng.gen::<f64>();
45 // get standard cauchy random number
46 // note that π/2 is not exactly representable, even if x=0.5 the result is finite
47 let comp_dev = (PI * x).tan();
48 // shift and scale according to parameters
49 let result = self.median + self.scale * comp_dev;
50 result
51 }
52 }
53
54 #[cfg(test)]
55 mod test {
56 use crate::distributions::Distribution;
57 use super::Cauchy;
58
59 fn median(mut numbers: &mut [f64]) -> f64 {
60 sort(&mut numbers);
61 let mid = numbers.len() / 2;
62 numbers[mid]
63 }
64
65 fn sort(numbers: &mut [f64]) {
66 numbers.sort_by(|a, b| a.partial_cmp(b).unwrap());
67 }
68
69 #[test]
70 #[cfg(not(miri))] // Miri doesn't support transcendental functions
71 fn test_cauchy_averages() {
72 // NOTE: given that the variance and mean are undefined,
73 // this test does not have any rigorous statistical meaning.
74 let cauchy = Cauchy::new(10.0, 5.0);
75 let mut rng = crate::test::rng(123);
76 let mut numbers: [f64; 1000] = [0.0; 1000];
77 let mut sum = 0.0;
78 for i in 0..1000 {
79 numbers[i] = cauchy.sample(&mut rng);
80 sum += numbers[i];
81 }
82 let median = median(&mut numbers);
83 println!("Cauchy median: {}", median);
84 assert!((median - 10.0).abs() < 0.4); // not 100% certain, but probable enough
85 let mean = sum / 1000.0;
86 println!("Cauchy mean: {}", mean);
87 // for a Cauchy distribution the mean should not converge
88 assert!((mean - 10.0).abs() > 0.4); // not 100% certain, but probable enough
89 }
90
91 #[test]
92 #[should_panic]
93 fn test_cauchy_invalid_scale_zero() {
94 Cauchy::new(0.0, 0.0);
95 }
96
97 #[test]
98 #[should_panic]
99 fn test_cauchy_invalid_scale_neg() {
100 Cauchy::new(0.0, -10.0);
101 }
102 }