rand_distr/
student_t.rs

1// Copyright 2018 Developers of the Rand project.
2// Copyright 2013 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 Student's t-distribution.
11
12use crate::{ChiSquared, ChiSquaredError};
13use crate::{Distribution, Exp1, Open01, StandardNormal};
14use num_traits::Float;
15use rand::Rng;
16#[cfg(feature = "serde")]
17use serde::{Deserialize, Serialize};
18
19/// The [Student t-distribution](https://en.wikipedia.org/wiki/Student%27s_t-distribution) `t(ν)`.
20///
21/// The t-distribution is a continuous probability distribution
22/// parameterized by degrees of freedom `ν` (`nu`), which
23/// arises when estimating the mean of a normally-distributed
24/// population in situations where the sample size is small and
25/// the population's standard deviation is unknown.
26/// It is widely used in hypothesis testing.
27///
28/// For `ν = 1`, this is equivalent to the standard
29/// [`Cauchy`](crate::Cauchy) distribution,
30/// and as `ν` diverges to infinity, `t(ν)` converges to
31/// [`StandardNormal`](crate::StandardNormal).
32///
33/// # Plot
34///
35/// The plot shows the t-distribution with various degrees of freedom.
36///
37/// ![T-distribution](https://raw.githubusercontent.com/rust-random/charts/main/charts/student_t.svg)
38///
39/// # Example
40///
41/// ```
42/// use rand_distr::{StudentT, Distribution};
43///
44/// let t = StudentT::new(11.0).unwrap();
45/// let v = t.sample(&mut rand::rng());
46/// println!("{} is from a t(11) distribution", v)
47/// ```
48#[derive(Clone, Copy, Debug, PartialEq)]
49#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
50pub struct StudentT<F>
51where
52    F: Float,
53    StandardNormal: Distribution<F>,
54    Exp1: Distribution<F>,
55    Open01: Distribution<F>,
56{
57    chi: ChiSquared<F>,
58    dof: F,
59}
60
61impl<F> StudentT<F>
62where
63    F: Float,
64    StandardNormal: Distribution<F>,
65    Exp1: Distribution<F>,
66    Open01: Distribution<F>,
67{
68    /// Create a new Student t-distribution with `ν` (nu)
69    /// degrees of freedom.
70    pub fn new(nu: F) -> Result<StudentT<F>, ChiSquaredError> {
71        Ok(StudentT {
72            chi: ChiSquared::new(nu)?,
73            dof: nu,
74        })
75    }
76}
77impl<F> Distribution<F> for StudentT<F>
78where
79    F: Float,
80    StandardNormal: Distribution<F>,
81    Exp1: Distribution<F>,
82    Open01: Distribution<F>,
83{
84    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> F {
85        let norm: F = rng.sample(StandardNormal);
86        norm * (self.dof / self.chi.sample(rng)).sqrt()
87    }
88}
89
90#[cfg(test)]
91mod test {
92    use super::*;
93
94    #[test]
95    fn test_t() {
96        let t = StudentT::new(11.0).unwrap();
97        let mut rng = crate::test::rng(205);
98        for _ in 0..1000 {
99            t.sample(&mut rng);
100        }
101    }
102
103    #[test]
104    fn student_t_distributions_can_be_compared() {
105        assert_eq!(StudentT::new(1.0), StudentT::new(1.0));
106    }
107}