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
const POW10: [f64; 13] = [
1.0, 10.0, 100.0, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12,
];
// Half away from zero on the binary64 value. A deviation is never negative,
// so there is no sign to restore.
fn round_to(x: f64, decimals: usize) -> f64 {
let scale = POW10[decimals];
let y = x * scale;
let mut r = y.floor();
if y - r >= 0.5 {
r += 1.0;
}
r / scale + 0.0
}
/// 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);
}
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;
round_to((squares / divisor).sqrt(), decimals as usize)
}
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()))
}