rs_stats/prob/std_dev.rs
1//! # Standard Deviation Calculation
2//!
3//! This module provides functions for calculating the standard deviation of a dataset.
4//!
5//! The standard deviation is a measure of the amount of variation or dispersion of a set of values.
6//! It is calculated as the square root of the variance.
7//!
8//! ## Supported Types
9//! The standard deviation function accepts any numeric type that implements `num_traits::ToPrimitive`,
10//! including:
11//! - Primitive integers (i8, i16, i32, i64, u8, u16, u32, u64)
12//! - Floating point numbers (f32, f64)
13//! - Big integers (BigInt, BigUint)
14//! - Any custom type that implements ToPrimitive
15
16use crate::prob::variance::variance;
17use num_traits::ToPrimitive;
18use std::fmt::Debug;
19
20/// Calculate the standard deviation of a dataset.
21///
22/// The standard deviation is a measure of the amount of variation or dispersion of a set of values.
23/// It is calculated as the square root of the variance.
24///
25/// # Arguments
26/// * `data` - A slice of numeric values implementing `ToPrimitive`
27///
28/// # Returns
29/// * `Some(f64)` - The standard deviation as a `f64` if the input slice is non-empty
30/// * `None` - If the input slice is empty
31///
32/// # Errors
33/// Returns `None` if:
34/// - The input slice is empty
35/// - Any value cannot be converted to f64
36///
37/// # Examples
38/// ```
39/// use rs_stats::prob::std_dev;
40///
41/// // Calculate standard deviation of integers
42/// let int_data = [1, 2, 3, 4, 5];
43/// let sd = std_dev(&int_data).unwrap();
44/// println!("Standard deviation of integers: {}", sd);
45///
46/// // Calculate standard deviation of floats
47/// let float_data = [1.0, 2.5, 3.0, 4.5, 5.0];
48/// let sd = std_dev(&float_data).unwrap();
49/// println!("Standard deviation of floats: {}", sd);
50///
51/// // Handle empty input
52/// let empty_data: &[i32] = &[];
53/// assert!(std_dev(empty_data).is_none());
54/// ```
55#[inline]
56pub fn std_dev<T>(data: &[T]) -> Option<f64>
57where
58 T: ToPrimitive + Debug,
59{
60 variance(data).map(|x| x.sqrt())
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 const EPSILON: f64 = 1e-9;
68
69 #[test]
70 fn test_population_std_dev_integers() {
71 let data = vec![1, 2, 3, 4, 5];
72 let result = std_dev(&data);
73 let expected = 2.0_f64.sqrt(); // sqrt of population variance (2.0)
74 assert!(
75 (result.unwrap() - expected).abs() < EPSILON,
76 "Population std_dev for integers should be sqrt(2.0)"
77 );
78 }
79
80 #[test]
81 fn test_population_std_dev_floats() {
82 let data = vec![1.0, 2.0, 3.0, 4.0, 5.0];
83 let result = std_dev(&data);
84 let expected = 2.0_f64.sqrt(); // sqrt of population variance (2.0)
85 assert!(
86 (result.unwrap() - expected).abs() < EPSILON,
87 "Population std_dev for floats should be sqrt(2.0)"
88 );
89 }
90
91 #[test]
92 fn test_population_std_dev_mixed_floats() {
93 let data = vec![1.5, 2.5, 3.5, 4.5, 5.5];
94 let result = std_dev(&data);
95 let expected = 2.0_f64.sqrt(); // sqrt of population variance (2.0)
96 assert!(
97 (result.unwrap() - expected).abs() < EPSILON,
98 "Population std_dev for mixed floats should be sqrt(2.0)"
99 );
100 }
101}