#[inline]
pub fn rolling_mean(values: &[f64], period: usize) -> Vec<f64> {
debug_assert!(period >= 1);
let n = values.len();
let mut out = vec![f64::NAN; n];
if n < period {
return out;
}
let mut sum: f64 = values[..period].iter().copied().sum();
out[period - 1] = sum / period as f64;
for i in period..n {
sum += values[i] - values[i - period];
out[i] = sum / period as f64;
}
out
}
pub fn wma_with_output(values: &[f64], period: usize, out: &mut [f64]) {
debug_assert!(period >= 1);
debug_assert_eq!(out.len(), values.len());
for v in out.iter_mut() {
*v = f64::NAN;
}
let n = values.len();
if n < period {
return;
}
let denom = (period * (period + 1) / 2) as f64;
let mut sw = 0.0_f64; for j in 0..period {
sw += values[j];
}
let mut w = 0.0_f64; for j in 0..period {
w += values[(period - 1) - j] * (period - j) as f64;
}
out[period - 1] = w / denom;
for i in period..n {
w = w + (period as f64) * values[i] - sw;
out[i] = w / denom;
sw += values[i] - values[i - period];
}
}
#[allow(dead_code)]
pub fn wma(values: &[f64], period: usize) -> Vec<f64> {
let mut out = vec![f64::NAN; values.len()];
wma_with_output(values, period, &mut out);
out
}
#[allow(dead_code)]
pub(crate) fn wma_naive(values: &[f64], period: usize) -> Vec<f64> {
debug_assert!(period >= 1);
let n = values.len();
let mut out = vec![f64::NAN; n];
if n < period {
return out;
}
let denom = (period * (period + 1) / 2) as f64;
for i in (period - 1)..n {
let mut s = 0.0;
for j in 0..period {
s += values[i - j] * (period - j) as f64;
}
out[i] = s / denom;
}
out
}
#[inline]
pub fn rolling_sum(values: &[f64], period: usize) -> Vec<f64> {
debug_assert!(period >= 1);
let n = values.len();
let mut out = vec![f64::NAN; n];
if n < period {
return out;
}
let start = match values.iter().position(|&x| !x.is_nan()) {
Some(s) => s,
None => return out,
};
if n - start < period {
return out;
}
let mut sum: f64 = values[start..start + period].iter().copied().sum();
out[start + period - 1] = sum;
for i in (start + period)..n {
sum += values[i] - values[i - period];
out[i] = sum;
}
out
}
#[inline]
pub fn rolling_mean_skip(values: &[f64], period: usize) -> Vec<f64> {
debug_assert!(period >= 1);
let n = values.len();
let mut out = vec![f64::NAN; n];
let start = match values.iter().position(|&x| !x.is_nan()) {
Some(s) => s,
None => return out,
};
if n - start < period {
return out;
}
let mut sum: f64 = values[start..start + period].iter().copied().sum();
out[start + period - 1] = sum / period as f64;
for i in (start + period)..n {
sum += values[i] - values[i - period];
out[i] = sum / period as f64;
}
out
}
#[inline]
pub fn rolling_var(values: &[f64], period: usize) -> Vec<f64> {
debug_assert!(period >= 1);
let n = values.len();
let mut out = vec![f64::NAN; n];
if n < period {
return out;
}
let p = period as f64;
let mut sx = values[..period].iter().copied().sum::<f64>();
let mut sxx = values[..period].iter().map(|v| v * v).sum::<f64>();
out[period - 1] = (sxx - sx * sx / p) / p;
for i in period..n {
sx += values[i] - values[i - period];
sxx += values[i] * values[i] - values[i - period] * values[i - period];
out[i] = (sxx - sx * sx / p) / p;
}
out
}
#[inline]
pub fn rolling_mean_var(values: &[f64], period: usize) -> (Vec<f64>, Vec<f64>) {
debug_assert!(period >= 1);
let n = values.len();
let mut mean = vec![f64::NAN; n];
let mut var = vec![f64::NAN; n];
if n < period {
return (mean, var);
}
let p = period as f64;
let mut sx = values[..period].iter().copied().sum::<f64>();
let mut sxx = values[..period].iter().map(|v| v * v).sum::<f64>();
mean[period - 1] = sx / p;
var[period - 1] = (sxx - sx * sx / p) / p;
for i in period..n {
sx += values[i] - values[i - period];
sxx += values[i] * values[i] - values[i - period] * values[i - period];
mean[i] = sx / p;
var[i] = (sxx - sx * sx / p) / p;
}
(mean, var)
}