Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
use super::funejson::Value; ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one
use super::math_round_float::round_float; ← from math.round-float ^1.0.0 · built alongside by fune
/// Population or sample standard deviation, two-pass.
///
/// The one-pass "mean of squares minus square of mean" shortcut cancels
/// catastrophically on large, close values; two passes do not.
///
/// # Panics
/// Panics on a non-finite value, an unknown kind, decimals outside 0..=12, an
/// empty list, or a sample of fewer than two values.
pub fn standard_deviation(values: &[f64], kind: &str, decimals: i64) -> f64 {
for v in values {
if !v.is_finite() {
panic!("values must be finite numbers, received {}", v);
}
}
if kind != "population" && kind != "sample" {
panic!("unknown standard deviation kind \"{}\"", kind);
}
// Checked up front as well as in round_float (same wording), so a bad
// decimals is reported before an empty list, as in 1.x.
if !(0..=12).contains(&decimals) {
panic!("decimals must be a whole number from 0 to 12, received {}", decimals);
}
let n = values.len();
if n == 0 {
panic!("values must not be empty");
}
if kind == "sample" && n < 2 {
panic!("sample standard deviation needs at least 2 values");
}
let mut sum = 0.0;
for v in values {
sum += *v;
}
let mean = sum / n as f64;
let mut squares = 0.0;
for v in values {
let d = *v - mean;
squares += d * d;
}
let divisor = if kind == "sample" { n - 1 } else { n } as f64;
// math.round-float rounds on the exact value of the double: 2.675 gives 2.67.
round_float((squares / divisor).sqrt(), decimals)
}
pub fn fune_vector(args: &[Value]) -> Value {
// Refuse what the typed signature cannot hold, with the wording TypeScript
// and Python use, rather than let the conversion below quietly change it.
for v in args[0].as_arr() {
if !matches!(v, Value::Int(_) | Value::Float(_)) {
panic!("values must be finite numbers, received {:?}", v);
}
}
let values: Vec<f64> = args[0].as_arr().iter().map(|v| v.as_f64()).collect();
Value::Float(standard_deviation(&values, args[1].as_str(), args[2].as_i64()))
}