Shared Rust kernels
catalogue/arithmetic
All modules · quoted at commit 9e1884369a67 of DnaCalc/DnaCalc. Comments are the source's own.
divide · 6 lines · calc-func/src/catalogue/arithmetic.rs on GitHubfn divide(
arguments: &[CalcValue],
services: &mut EvalServices<'_>,
) -> Result<CalcValue, FunctionFault> {
binary(DIVIDE, arguments, services, |site, a, b| Ok(flushed(site.divide(a, b)?)))
}
Used by 2 functions.
flushed · 5 lines · calc-func/src/catalogue/arithmetic.rs on GitHub/// A product or quotient as Excel publishes it: +0 below the normal range (see the module
/// documentation).
fn flushed(x: f64) -> f64 {
if x.is_subnormal() { 0.0 } else { x }
}
Used by 3 functions.
power_value · 5 lines · calc-func/src/catalogue/arithmetic.rs on GitHub/// The kernel distinguishes flushed integer/reciprocal results from retained fractional
/// subnormals. Both POWER and the operator publish that result through the same measured policy.
pub(super) fn power_value(site: &Site<'_>, x: f64, y: f64) -> Step<CalcValue> {
super::kit::out_with_subnormal(site, Ok(raise(site, x, y)?))
}
Used by 2 functions.
binary · 9 lines · calc-func/src/catalogue/arithmetic.rs on GitHubfn binary<'m>(
id: FunctionId,
arguments: &[CalcValue],
services: &EvalServices<'m>,
operation: fn(&Site<'m>, f64, f64) -> Step<f64>,
) -> Result<CalcValue, FunctionFault> {
let site = Site::new(id, services);
Site::finish(operands(&site, arguments).and_then(|(a, b)| site.number(operation(&site, a, b)?)))
}
Used by 5 functions.
operands · 6 lines · calc-func/src/catalogue/arithmetic.rs on GitHubfn operands(site: &Site<'_>, arguments: &[CalcValue]) -> Step<(f64, f64)> {
site.scalar_operands(arguments)?;
let a = site.number_argument(0, &arguments[0])?;
let b = site.number_argument(1, &arguments[1])?;
Ok((a, b))
}
Used by 6 functions.
raise · 38 lines · calc-func/src/catalogue/arithmetic.rs on GitHub/// `x ^ y`. The cases decided without a power algorithm keep their measured rule: 0 to a
/// negative power is #DIV/0! and 0 to the power 0 is #NUM!; the exponents 0, 1 and 2 and the
/// bases 0 and 1 give their exact or singly rounded result. The negative unit base retains the
/// kernel's exponent admission, with exact unit results. Every other power, a reciprocal or a
/// negative base with a fractional exponent included, is OxFunc's Excel power kernel
/// (ported/power_fn.rs, OxFunc 6fca3518): binary exponentiation with x87-staged products for an
/// integer exponent, a decimal scale for a base of 10, `exp(y ln x)` on the x87 backend for a
/// fractional one, and Excel's real-root rule for a negative base (accepted when `1/y`, read to
/// 15 significant digits, is an odd integer; #NUM! otherwise). That kernel is an arithmetic site.
pub(super) fn raise(site: &Site<'_>, x: f64, y: f64) -> Step<f64> {
if x == 0.0 {
return if y == 0.0 {
Err(Exit::Error(WorksheetErrorCode::Num))
} else if y < 0.0 {
Err(Exit::Error(WorksheetErrorCode::Div0))
} else {
Ok(0.0)
};
}
if x < 0.0 && y.fract() != 0.0 {
return power_algorithm(site, x, y);
}
if y == 0.0 || x == 1.0 {
Ok(1.0)
} else if y == 1.0 {
Ok(x)
} else if x == -1.0 {
// Unit results are exact, but the kernel still owns integer-width admission.
crate::ported::power_fn::power_kernel(x, y).map_err(Exit::Error)
} else if y == 2.0 {
// A square below the normal range is +0, as Excel gives it (1E-160^2 in the catalogue
// oracle's sheet f1_power), and as the power kernel flushes it.
let square = site.multiply(x, x)?;
Ok(if square.is_subnormal() { 0.0 } else { square })
} else {
power_algorithm(site, x, y)
}
}
Used by 2 functions.
power_algorithm · 5 lines · calc-func/src/catalogue/arithmetic.rs on GitHub/// The powers that need a power algorithm: OxFunc's Excel power kernel, at one arithmetic site.
fn power_algorithm(site: &Site<'_>, x: f64, y: f64) -> Step<f64> {
site.binary64()?;
crate::ported::power_fn::power_kernel(x, y).map_err(Exit::Error)
}
Used by 2 functions.