Skip to main content

rs_stats/prob/
average.rs

1//! # Average Calculation
2//!
3//! This module provides functions for calculating the arithmetic mean (average) of a dataset.
4//!
5//! The average is calculated as the sum of all values divided by the number of values.
6//!
7//! ## Supported Types
8//! The average function accepts any numeric type that implements `num_traits::ToPrimitive`,
9//! including:
10//! - Primitive integers (i8, i16, i32, i64, u8, u16, u32, u64)
11//! - Floating point numbers (f32, f64)
12//! - Big integers (BigInt, BigUint)
13//! - Any custom type that implements ToPrimitive
14
15use crate::error::{StatsError, StatsResult};
16use num_traits::ToPrimitive;
17use std::fmt::Debug;
18
19/// Calculate the arithmetic mean (average) of a dataset.
20///
21/// The average is calculated as the sum of all values divided by the number of values.
22///
23/// # Arguments
24/// * `data` - A slice of numeric values implementing `ToPrimitive`
25///
26/// # Returns
27/// * `StatsResult<f64>` - The average as a `f64`, or an error if the input is invalid
28///
29/// # Errors
30/// Returns `StatsError::EmptyData` if the input slice is empty.
31/// Returns `StatsError::ConversionError` if any value cannot be converted to f64.
32///
33/// # Examples
34/// ```
35/// use rs_stats::prob::average;
36///
37/// // Calculate average of integers
38/// let int_data = [1, 2, 3, 4, 5];
39/// let avg = average(&int_data)?;
40/// println!("Average of integers: {}", avg);
41///
42/// // Calculate average of floats
43/// let float_data = [1.0, 2.5, 3.0, 4.5, 5.0];
44/// let avg = average(&float_data)?;
45/// println!("Average of floats: {}", avg);
46///
47/// // Handle empty input
48/// let empty_data: &[i32] = &[];
49/// assert!(average(empty_data).is_err());
50/// # Ok::<(), rs_stats::StatsError>(())
51/// ```
52#[inline]
53pub fn average<T>(data: &[T]) -> StatsResult<f64>
54where
55    T: ToPrimitive + Debug,
56{
57    if data.is_empty() {
58        return Err(StatsError::empty_data(
59            "prob::average: Cannot calculate average of empty dataset",
60        ));
61    }
62
63    let mut sum = 0.0;
64
65    for (i, x) in data.iter().enumerate() {
66        let v = x.to_f64().ok_or_else(|| {
67            StatsError::conversion_error(format!(
68                "prob::average: Failed to convert value at index {} to f64",
69                i
70            ))
71        })?;
72
73        sum += v;
74    }
75
76    Ok(sum / data.len() as f64)
77}
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn test_average_integers() {
84        let data = vec![1, 2, 3, 4, 5];
85        let result = average(&data).unwrap();
86        assert_eq!(result, 3.0);
87    }
88
89    #[test]
90    fn test_average_floats() {
91        let data = vec![1.5, 2.5, 3.5, 4.5];
92        let result = average(&data).unwrap();
93        assert_eq!(result, 3.0);
94    }
95
96    #[test]
97    fn test_average_mixed_types() {
98        let data = vec![1.0, 2.0, 3.0, 4.5, 5.5]; // All elements are f64
99        let result = average(&data).unwrap();
100        assert_eq!(result, 3.2);
101    }
102
103    #[test]
104    fn test_average_empty_slice() {
105        let data: Vec<f64> = Vec::new();
106        let result = average(&data);
107        assert!(result.is_err());
108        assert!(matches!(result.unwrap_err(), StatsError::EmptyData { .. }));
109    }
110
111    #[test]
112    fn test_average_single_value() {
113        let data = vec![10.0];
114        let result = average(&data).unwrap();
115        assert_eq!(result, 10.0);
116    }
117}