1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
use crate::special::Error;
/// A module containing functions to work with the Gaussian (Normal) distribution.
pub struct Gaussian;
impl Gaussian {
/// Calculates the Probability Density Function (PDF) on a Normal/Gaussian distribution.
///
/// # Parameters
///
/// - `x_value`: The value at which to evaluate the PDF.
/// - `mean`: The mean (average) of the distribution.
/// - `sd`: The standard deviation of the distribution.
///
/// # Returns
///
/// The calculated PDF.
///
/// # Example
///
/// ```rust
/// use numerilib::stats::distr::Gaussian;
///
/// let x_value = 0.5;
/// let mean = 0.0;
/// let sd = 1.0;
///
/// let normalpdf = Gaussian::pdf(x_value, mean, sd);
///
/// println!("PDF at x = {}: {}", x_value, normalpdf);
/// ```
/// <hr/>
pub fn pdf(
x_value: impl Into<f64> + Copy,
mean: impl Into<f64> + Copy,
sd: impl Into<f64> + Copy,
) -> f64 {
(1.0 / (sd.into() * (std::f64::consts::TAU).sqrt()))
* (std::f64::consts::E)
.powf((-1.0 / 2.0) * ((x_value.into() - mean.into()) / sd.into()).powi(2))
}
/// Calculates the Cumulative Distribution Function (CDF) on a Normal/Gaussian distribution.
///
/// The CDF is calculated by converting the value to a z-score and using the Error function.
///
/// # Parameters
///
/// - `bound`: The upper bound of integration for the CDF.
/// - `mean`: The mean (average) of the distribution.
/// - `sd`: The standard deviation of the distribution.
///
/// # Returns
///
/// The calculated CDF.
///
/// # Example
///
/// ```rust
/// use numerilib::stats::distr::Gaussian;
///
/// let bound = 1.96;
/// let mean = 0.0;
/// let sd = 1.0;
///
/// let normalcdf = Gaussian::cdf(bound, mean, sd);
///
/// println!("CDF at bound = {}: {}", bound, normalcdf);
/// ```
/// <hr/>
pub fn cdf(bound: f64, mean: f64, sd: f64) -> f64 {
let z = (bound - mean) / (sd * std::f64::consts::SQRT_2);
let erfc = Error::erfc(z);
erfc / 2_f64
}
/// Calculates a 2 tailed Cumulative Distribution Function (CDF) on a Normal/Gaussian distribution.
///
/// The 2-tailed CDF is calculated by summing the CDF values for both tails.
///
/// # Parameters
///
/// - `lower`: The lower bound of integration for the CDF.
/// - `upper`: The upper bound of integration for the CDF.
/// - `mean`: The mean (average) of the distribution.
/// - `sd`: The standard deviation of the distribution.
///
/// # Returns
///
/// The calculated 2-tailed CDF.
///
/// # Example
///
/// ```rust
/// use numerilib::stats::distr::Gaussian;
///
/// let lower = -1.0;
/// let upper = 1.0;
/// let mean = 0.0;
/// let sd = 1.0;
///
/// let normalcdf = Gaussian::tailcdf(lower, upper, mean, sd);
///
/// println!("2-tailed CDF between {} and {}: {}", lower, upper, normalcdf);
/// ```
/// <hr/>
pub fn tailcdf(lower: f64, upper: f64, mean: f64, sd: f64) -> f64 {
if lower > upper {
return 0_f64;
}
Self::cdf(lower, mean, sd) - Self::cdf(upper, mean, sd)
}
/// Calculates the Inverse Normal (Quantile) function.
///
/// This function is used to find the value that corresponds to a given cumulative probability.
/// It recreates the InvNorm function in the Ti-83 & 84 calculators.
///
/// # Parameters
///
/// - `area`: The cumulative probability for which to find the quantile.
/// - `mean`: The mean (average) of the distribution.
/// - `sd`: The standard deviation of the distribution.
/// - `tail`: The tail side for which to find the quantile ("Right" or "Left").
///
/// # Returns
///
/// - The calculated quantile value on success.
/// - An error message on failure.
///
/// # Example
///
/// ```rust
/// use numerilib::stats::distr::Gaussian;
///
/// let area = 0.975;
/// let mean = 0.0;
/// let sd = 1.0;
/// let tail = "Left";
///
/// let invnorm = Gaussian::inv(area, mean, sd, tail).unwrap();
///
/// println!("Inverse normal quantile for area {}: {}", area, invnorm);
/// ```
/// <hr/>
pub fn inv<T: AsRef<str> + Copy>(
area: f64,
mean: impl Into<f64> + Copy,
sd: impl Into<f64> + Copy,
tail: T,
) -> Result<f64, String> {
let tail_str = tail.as_ref();
let function: f64 =
(std::f64::consts::SQRT_2 * sd.into()) * (Error::inverf(-2_f64 * area + 1_f64));
let tail_val: f64 = if tail_str.eq_ignore_ascii_case("Right") {
function + mean.into()
} else if tail_str.eq_ignore_ascii_case("Left") {
(-1_f64 * function) + mean.into()
} else {
return Err("Tail side Invalid, the only options are:\nRight\nleft".to_string());
};
let rounded_val =
if (tail_val.ceil() - 1e-7) < tail_val || (tail_val.floor() + 1e-7) > tail_val {
(tail_val * 1e+7).round() / 1e+7
} else {
tail_val
};
Ok(rounded_val)
}
/// Calculates the Median Absolute Deviation (MAD) on a Normal/Gaussian distribution.
///
/// MAD is a robust measure of the variability of a univariate sample of quantitative data.
///
/// # Parameters
///
/// - `sigma`: The standard deviation multiplier.
///
/// # Returns
///
/// The calculated MAD value.
///
/// # Example
///
/// ```rust
/// use numerilib::stats::distr::Gaussian;
///
/// let sigma = 1.5;
///
/// let mad = Gaussian::mad(sigma);
///
/// println!("MAD for sigma {}: {}", sigma, mad);
/// ```
/// <hr/>
pub fn mad(sigma: f64) -> f64 {
Error::inverf(1_f64 / 2_f64) * sigma * std::f64::consts::SQRT_2
}
}