Shared Rust kernels

ported/depreciation_family

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

validate_finite · 7 lines · calc-func/src/ported/depreciation_family.rs on GitHub
fn validate_finite(values: &[f64]) -> Result<(), WorksheetErrorCode> {
    if values.iter().all(|value| value.is_finite()) {
        Ok(())
    } else {
        Err(WorksheetErrorCode::Num)
    }
}

Used by 5 functions.

publish_depreciation · 9 lines · calc-func/src/ported/depreciation_family.rs on GitHub
fn publish_depreciation(value: f64) -> Result<f64, WorksheetErrorCode> {
    if !value.is_finite() {
        Err(WorksheetErrorCode::Num)
    } else if value.abs() < f64::MIN_POSITIVE {
        Ok(0.0)
    } else {
        Ok(value)
    }
}

Used by 4 functions.

depreciation_integer_power · 13 lines · calc-func/src/ported/depreciation_family.rs on GitHub
fn depreciation_integer_power(mut base: f64, mut exponent: u32) -> f64 {
    let mut product = 1.0;
    while exponent > 0 {
        if exponent & 1 != 0 {
            product = crate::ported::excel_numeric::excel_x87_mul(product, base);
        }
        exponent >>= 1;
        if exponent > 0 {
            base = crate::ported::excel_numeric::excel_x87_mul(base, base);
        }
    }
    product
}

Used by 3 functions.

ddb_period_depreciation · 46 lines · calc-func/src/ported/depreciation_family.rs on GitHub
fn ddb_period_depreciation(
    cost: f64,
    salvage: f64,
    life: f64,
    period: f64,
    factor: f64,
) -> Result<f64, WorksheetErrorCode> {
    let rate = crate::ported::excel_numeric::excel_x87_div(factor, life);
    // DDB publishes its division stage before the cost product. A subnormal
    // rate is zero even if multiplication by cost could make it normal again.
    let rate = if rate.abs() < f64::MIN_POSITIVE {
        0.0
    } else {
        rate
    };
    // The financial power dispatch shares POWER's bounded integer substrate,
    // but its count sentinel is u32::MAX rather than the worksheet wrapper's
    // wider integer range (W111 large-period discriminator).
    let power = if period <= 1.0 {
        1.0
    } else {
        let base = crate::ported::excel_numeric::excel_x87_sub(1.0, rate).max(0.0);
        let exponent = period - 1.0;
        if exponent.fract() == 0.0 && exponent < u32::MAX as f64 {
            // Each accumulator product is rounded through the x87 store. The
            // ordinary POWER binary64 body differs on large integer periods.
            let value = depreciation_integer_power(base, exponent as u32);
            if value.abs() < f64::MIN_POSITIVE {
                0.0
            } else {
                value
            }
        } else if exponent >= u32::MAX as f64 && base != 0.0 {
            crate::ported::excel_numeric::excel_pow_positive(base, exponent)
        } else {
            crate::ported::power_fn::power_kernel(base, exponent)?
        }
    };
    let book = crate::ported::excel_numeric::excel_x87_mul(cost, power);
    let declining = crate::ported::excel_numeric::excel_x87_mul(book, rate);
    // Overflow is observable before salvage clipping, including cost<salvage.
    if !declining.is_finite() {
        return Err(WorksheetErrorCode::Num);
    }
    publish_depreciation(declining.min(book - salvage).max(0.0))
}

Used by 2 functions.