Shared Rust kernels

ported/variance_common

All modules · quoted at commit 9e1884369a67 of DnaCalc/DnaCalc. Comments are the source's own.

variance_from_values · 52 lines · calc-func/src/ported/variance_common.rs on GitHub
pub fn variance_from_values(
    values: &[f64],
    divisor: VarianceDivisor,
) -> Result<f64, WorksheetErrorCode> {
    if values.is_empty() {
        return Err(WorksheetErrorCode::Div0);
    }
    if matches!(divisor, VarianceDivisor::Sample) && values.len() < 2 {
        return Err(WorksheetErrorCode::Div0);
    }

    // dc-j9k.13: the raw-moment identities have different store boundaries
    // for sample and population. Every arithmetic assignment stores from
    // x87 PC64, including the squares and the final division. Six original
    // bank controls distinguish these steps from ordinary binary64.
    let count = values.len() as f64;
    let total = values.iter().fold(0.0, |s, &x| add(s, x));
    let squares = values.iter().fold(0.0, |q, &x| add(q, mul(x, x)));
    let square_total = mul(total, total);
    let (left, correction) = match divisor {
        VarianceDivisor::Sample => (squares, div(square_total, count)),
        VarianceDivisor::Population => (mul(count, squares), square_total),
    };
    let numerator = sub(left, correction);
    let denom = match divisor {
        VarianceDivisor::Population => count,
        VarianceDivisor::Sample => (values.len() - 1) as f64,
    };
    let raw_divisor = match divisor {
        VarianceDivisor::Population => mul(count, denom),
        VarianceDivisor::Sample => denom,
    };
    let variance = div(numerator, raw_divisor);
    let mean = div(total, count);
    // R25 scalar-cell bisections distinguish these stored comparisons from
    // numerator<0.01*squares, a resident product, and strict variance*1000<mean.
    // The original negative-mean controls also require the absolute mean.
    // Range/array transfer at the new edges remains a separate Excel question.
    // Nonfinite raw moments take the centered pass to retain finite centered
    // results when an intermediate square or count*squares overflows.
    let cancellation = div(div(square_total, count), squares) > 0.99;
    let small_variance = mul(variance, 1000.0) <= mean.abs();
    if !variance.is_finite() || cancellation || small_variance {
        let centered = values.iter().fold(0.0, |q, &x| {
            let delta = sub(x, mean);
            add(q, mul(delta, delta))
        });
        Ok(div(centered, denom))
    } else {
        Ok(variance)
    }
}

Used by 28 functions.

stdev_from_values · 6 lines · calc-func/src/ported/variance_common.rs on GitHub
pub fn stdev_from_values(
    values: &[f64],
    divisor: VarianceDivisor,
) -> Result<f64, WorksheetErrorCode> {
    variance_from_values(values, divisor).map(excel_sqrt_staged)
}

Used by 28 functions.