pub fn ema_with_output(values: &[f64], period: usize, out: &mut [f64]) {
debug_assert!(period >= 1);
debug_assert_eq!(out.len(), values.len());
let n = values.len();
let start = match values.iter().position(|&x| !x.is_nan()) {
Some(s) => s,
None => {
for v in out.iter_mut() {
*v = f64::NAN;
}
return;
}
};
if n - start < period {
for v in out.iter_mut() {
*v = f64::NAN;
}
return;
}
for v in out[..start + period - 1].iter_mut() {
*v = f64::NAN;
}
let seed: f64 = values[start..start + period].iter().copied().sum::<f64>() / period as f64;
out[start + period - 1] = seed;
let k = 2.0 / (period as f64 + 1.0);
let mut prev = seed;
let v = &values[start + period..];
let o = &mut out[start + period..];
let len = v.len().min(o.len());
for i in 0..len {
prev = (v[i] - prev).mul_add(k, prev);
o[i] = prev;
}
}
pub fn ema(values: &[f64], period: usize) -> Vec<f64> {
let mut out = vec![f64::NAN; values.len()];
ema_with_output(values, period, &mut out);
out
}
#[inline]
pub fn nested_ema_with_output<const L: usize, F>(
values: &[f64],
period: usize,
mut combine: F,
out: &mut [f64],
) where
F: FnMut(&[f64; L]) -> f64,
{
debug_assert!(period >= 1);
debug_assert_eq!(out.len(), values.len());
let n = values.len();
if n == 0 {
return;
}
let k = 2.0 / (period as f64 + 1.0);
let pk = period as f64;
let nan = f64::NAN;
let mut e = [nan; L];
let mut prev = [nan; L];
let mut seed_sum = [0.0f64; L];
let mut seed_n = [0usize; L];
let mut seeded = [false; L];
for i in 0..n {
let v1 = values[i];
if !seeded[0] {
if !v1.is_nan() {
seed_sum[0] += v1;
seed_n[0] += 1;
if seed_n[0] == period {
e[0] = seed_sum[0] / pk;
seeded[0] = true;
prev[0] = e[0];
}
}
} else {
e[0] = (v1 - prev[0]).mul_add(k, prev[0]);
prev[0] = e[0];
}
for l in 1..L {
let src = e[l - 1];
if !seeded[l] {
if !src.is_nan() {
seed_sum[l] += src;
seed_n[l] += 1;
if seed_n[l] == period {
e[l] = seed_sum[l] / pk;
seeded[l] = true;
prev[l] = e[l];
}
}
} else {
e[l] = (src - prev[l]).mul_add(k, prev[l]);
prev[l] = e[l];
}
}
out[i] = if seeded[L - 1] { combine(&e) } else { nan };
}
}
#[inline(always)]
pub fn wilder_step(prev: f64, x: f64, k: f64) -> f64 {
prev + (x - prev) * k
}
#[inline(always)]
pub fn wilder_step_sum(prev: f64, x: f64, k: f64) -> f64 {
prev * (1.0 - k) + x
}
pub fn wilder_with_output(values: &[f64], period: usize, out: &mut [f64]) {
debug_assert!(period >= 1);
debug_assert_eq!(out.len(), values.len());
let n = values.len();
for v in out.iter_mut() {
*v = f64::NAN;
}
let start = match values.iter().position(|&x| !x.is_nan()) {
Some(s) => s,
None => return,
};
if n - start < period {
return;
}
let seed: f64 = values[start..start + period].iter().copied().sum::<f64>() / period as f64;
out[start + period - 1] = seed;
let k = 1.0 / period as f64;
let mut prev = seed;
for i in (start + period)..n {
prev = wilder_step(prev, values[i], k);
out[i] = prev;
}
}
#[inline]
pub fn ema_wilder(values: &[f64], period: usize) -> Vec<f64> {
debug_assert!(period >= 1);
let mut out = vec![f64::NAN; values.len()];
wilder_with_output(values, period, &mut out);
out
}