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/// 
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}