Shared Rust kernels

ported/percentrank_common

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

percentrank · 36 lines · calc-func/src/ported/percentrank_common.rs on GitHub
pub fn percentrank(
    values: &mut [f64],
    x: f64,
    significance: i64,
    mode: PercentRankMode,
) -> Result<f64, WorksheetErrorCode> {
    if values.is_empty() {
        return Err(WorksheetErrorCode::NA);
    }
    if significance <= 0 {
        return Err(WorksheetErrorCode::Num);
    }
    values.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
    let first = values[0];
    let last = values[values.len() - 1];
    if x < first || x > last {
        return Err(WorksheetErrorCode::NA);
    }

    let base =
        match values.binary_search_by(|v| v.partial_cmp(&x).unwrap_or(std::cmp::Ordering::Equal)) {
            Ok(idx) => exact_rank(idx, values.len(), mode),
            Err(upper) => {
                if upper == 0 || upper >= values.len() {
                    return Err(WorksheetErrorCode::NA);
                }
                let lower = upper - 1;
                let lower_x = values[lower];
                let upper_x = values[upper];
                let lower_rank = exact_rank(lower, values.len(), mode);
                let upper_rank = exact_rank(upper, values.len(), mode);
                lower_rank + (x - lower_x) * (upper_rank - lower_rank) / (upper_x - lower_x)
            }
        };
    Ok(truncate_to_decimal_places(base, significance))
}

Used by 3 functions.

exact_rank · 6 lines · calc-func/src/ported/percentrank_common.rs on GitHub
fn exact_rank(index: usize, len: usize, mode: PercentRankMode) -> f64 {
    match mode {
        PercentRankMode::Inclusive => index as f64 / (len as f64 - 1.0),
        PercentRankMode::Exclusive => (index as f64 + 1.0) / (len as f64 + 1.0),
    }
}

Used by 3 functions.

truncate_to_decimal_places · 9 lines · calc-func/src/ported/percentrank_common.rs on GitHub
/// The rank truncated to `places` decimal places, trunc(value*10^places)/10^places: Excel's
/// `significance` counts decimal places, not significant digits (dc-j9k: 301 of 301
/// PERCENTRANK, PERCENTRANK.INC and PERCENTRANK.EXC readings in the catalogue oracle's sheet
/// dcj9k_statistics; PERCENTRANK.INC(...,5.93) is 0.037, where three significant digits
/// gave 0.0373).
fn truncate_to_decimal_places(value: f64, places: i64) -> f64 {
    let scale = 10f64.powi(places.min(308) as i32);
    (value * scale).trunc() / scale
}

Used by 3 functions.