#[inline]
pub fn rolling_std(data: &[f64], window: usize) -> Vec<f64> {
rolling_std_welford(data, window) }
pub fn rolling_std_welford(data: &[f64], window: usize) -> Vec<f64> {
let n = data.len();
if window == 0 || window > n {
return vec![f64::NAN; n];
}
let mut result = vec![f64::NAN; n];
let mut mean = 0.0;
let mut m2 = 0.0;
for i in 0..window {
let delta = data[i] - mean;
mean += delta / (i + 1) as f64;
let delta2 = data[i] - mean;
m2 += delta * delta2;
}
result[window - 1] = (m2 / window as f64).sqrt();
for i in window..n {
let old_val = data[i - window];
let new_val = data[i];
let old_mean = mean;
mean -= (old_val - mean) / window as f64;
m2 -= (old_val - mean) * (old_val - old_mean);
let delta = new_val - mean;
mean += delta / window as f64;
let delta2 = new_val - mean;
m2 += delta * delta2;
result[i] = (m2.max(0.0) / window as f64).sqrt();
}
result
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rolling_std_welford() {
let data = vec![2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0];
let result = rolling_std_welford(&data, 4);
for i in 0..3 {
assert!(result[i].is_nan());
}
assert!(result[3] > 0.0 && result[3] < 2.0); assert!(result[7] > 0.0 && result[7] < 3.0); }
}