Shared Rust kernels

catalogue/math

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

raw · 5 lines · calc-func/src/catalogue/math.rs on GitHub
/// A one-argument kernel whose raw result Excel publishes under `policy`.
fn raw(site: &Site<'_>, a: &[CalcValue], policy: ExcelRealPolicy, kernel: fn(f64) -> f64) -> Step<CalcValue> {
    let x = num(site, a, 0)?;
    out(site, policy.publish(x, kernel(x)))
}

Used by 9 functions.

unary · 5 lines · calc-func/src/catalogue/math.rs on GitHub
/// A one-argument kernel that publishes its own result.
fn unary(site: &Site<'_>, a: &[CalcValue], kernel: fn(f64) -> Result<f64, WorksheetErrorCode>) -> Step<CalcValue> {
    let x = num(site, a, 0)?;
    out(site, kernel(x))
}

Used by 17 functions.

binary · 10 lines · calc-func/src/catalogue/math.rs on GitHub
/// A two-argument kernel.
fn binary(
    site: &Site<'_>,
    a: &[CalcValue],
    kernel: fn(f64, f64) -> Result<f64, WorksheetErrorCode>,
) -> Step<CalcValue> {
    let x = num(site, a, 0)?;
    let y = num(site, a, 1)?;
    out(site, kernel(x, y))
}

Used by 3 functions.

integer_groups · 47 lines · calc-func/src/catalogue/math.rs on GitHub
/// GCD's and LCM's integers: each argument's numbers (a held logical is #VALUE!, a blank cell of
/// a multi-cell argument is 0 and a direct omitted argument after the first is skipped), each at
/// least 0 and at most 2^53, truncated.
fn integer_groups(
    site: &Site<'_>,
    a: &[CalcValue],
    services: &mut crate::call::EvalServices<'_>,
) -> Step<Vec<i64>> {
    let mut numbers = Vec::new();
    let mut any = false;
    for (index, argument) in a.iter().enumerate() {
        if argument.is_missing() {
            if index == 0 {
                return fail(WorksheetErrorCode::NA);
            }
            continue;
        }
        let Grid { cells, held, .. } = grid(site, a, index, services)?;
        let multi = cells.len() > 1;
        for cell in &cells {
            match cell.core_ref() {
                CoreRef::Empty | CoreRef::Missing => {
                    if multi {
                        numbers.push(0.0);
                        any = true;
                    }
                }
                CoreRef::Logical(_) => return fail(WorksheetErrorCode::Value),
                _ => {
                    numbers.push(site.number_argument(index, cell)?);
                    any = true;
                }
            }
        }
        let _ = held;
    }
    if !any {
        return fail(WorksheetErrorCode::Value);
    }
    if numbers
        .iter()
        .any(|n| !n.is_finite() || *n < 0.0 || *n > k::gcd_lcm_common::GCD_LCM_LIMIT)
    {
        return fail(WorksheetErrorCode::Num);
    }
    Ok(numbers.into_iter().map(|n| n.trunc() as i64).collect())
}

Used by 2 functions.

sum_pairwise · 27 lines · calc-func/src/catalogue/math.rs on GitHub
/// SUMX2MY2, SUMX2PY2 and SUMXMY2: `term` summed over the positions where both arguments hold a
/// number; arguments of different shapes are #N/A, an error is the result, and no such position
/// is #DIV/0!.
fn sum_pairwise(
    site: &Site<'_>,
    a: &[CalcValue],
    services: &mut crate::call::EvalServices<'_>,
    term: fn(f64, f64) -> f64,
) -> Step<CalcValue> {
    let left = numeric_cells(site, a, 0, services)?;
    let right = numeric_cells(site, a, 1, services)?;
    if left.0 != right.0 {
        return fail(WorksheetErrorCode::NA);
    }
    let mut seen = false;
    let mut sum = 0.0;
    for (x, y) in left.1.iter().zip(&right.1) {
        if let (Some(x), Some(y)) = (x, y) {
            seen = true;
            sum += term(*x, *y);
        }
    }
    if !seen {
        return fail(WorksheetErrorCode::Div0);
    }
    site.number(sum)
}

Used by 3 functions.

numeric_cells · 19 lines · calc-func/src/catalogue/math.rs on GitHub
/// An argument's shape and, per cell, its number (`None` for text, a logical or a blank); an
/// error cell is the result.
fn numeric_cells(
    site: &Site<'_>,
    a: &[CalcValue],
    index: usize,
    services: &mut crate::call::EvalServices<'_>,
) -> Step<NumericCells> {
    let g = grid(site, a, index, services)?;
    let mut cells = Vec::with_capacity(g.cells.len());
    for cell in &g.cells {
        cells.push(match cell.core_ref() {
            CoreRef::Number(n) => Some(n),
            CoreRef::Error(code) => return fail(code),
            _ => None,
        });
    }
    Ok(((g.rows, g.cols), cells))
}

Used by 3 functions.

matrix · 23 lines · calc-func/src/catalogue/math.rs on GitHub
/// An argument as a matrix of numbers: every cell must hold a number (an error cell is the
/// result, anything else #VALUE!); a single direct value must be a number.
fn matrix(
    site: &Site<'_>,
    a: &[CalcValue],
    index: usize,
    services: &mut crate::call::EvalServices<'_>,
) -> Step<Vec<Vec<f64>>> {
    let g = grid(site, a, index, services)?;
    let mut rows = Vec::with_capacity(g.rows);
    for r in 0..g.rows {
        let mut row = Vec::with_capacity(g.cols);
        for cell in &g.cells[r * g.cols..(r + 1) * g.cols] {
            match cell.core_ref() {
                CoreRef::Number(n) => row.push(n),
                CoreRef::Error(code) => return fail(code),
                _ => return fail(WorksheetErrorCode::Value),
            }
        }
        rows.push(row);
    }
    Ok(rows)
}

Used by 3 functions.