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::error::StatsResult;
17use crate::prob::variance;
18use num_traits::ToPrimitive;
19use std::fmt::Debug;
20
21/// Calculate the standard deviation of a dataset.
22///
23/// The standard deviation is a measure of the amount of variation or dispersion of a set of values.
24/// It is calculated as the square root of the variance.
25///
26/// # Arguments
27/// * `data` - A slice of numeric values implementing `ToPrimitive`
28///
29/// # Returns
30/// * `StatsResult<f64>` - The standard deviation as a `f64`, or an error if the input is invalid
31///
32/// # Errors
33/// Returns `StatsError::EmptyData` if the input slice is empty.
34/// Returns `StatsError::ConversionError` if any value cannot be converted to f64.
35///
36/// # Examples
37/// ```
38/// use rs_stats::prob::std_dev;
39///
40/// // Calculate standard deviation of integers
41/// let int_data = [1, 2, 3, 4, 5];
42/// let sd = std_dev(&int_data)?;
43/// println!("Standard deviation of integers: {}", sd);
44///
45/// // Calculate standard deviation of floats
46/// let float_data = [1.0, 2.5, 3.0, 4.5, 5.0];
47/// let sd = std_dev(&float_data)?;
48/// println!("Standard deviation of floats: {}", sd);
49///
50/// // Handle empty input
51/// let empty_data: &[i32] = &[];
52/// assert!(std_dev(empty_data).is_err());
53/// # Ok::<(), rs_stats::StatsError>(())
54/// ```
55#[inline]
56pub fn std_dev<T>(data: &[T]) -> StatsResult<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).unwrap();
73        let expected = 2.0_f64.sqrt(); // sqrt of population variance (2.0)
74        assert!(
75            (result - 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).unwrap();
84        let expected = 2.0_f64.sqrt(); // sqrt of population variance (2.0)
85        assert!(
86            (result - 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).unwrap();
95        let expected = 2.0_f64.sqrt(); // sqrt of population variance (2.0)
96        assert!(
97            (result - expected).abs() < EPSILON,
98            "Population std_dev for mixed floats should be sqrt(2.0)"
99        );
100    }
101}