Shared Rust kernels

ported/complex_decimal

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

nearest_even · 10 lines · calc-func/src/ported/complex_decimal.rs on GitHub
/// Round a positive exact integer quotient to nearest, ties to even.
fn nearest_even(numerator: u128, denominator: u128) -> u128 {
    let quotient = numerator / denominator;
    let remainder = numerator % denominator;
    // The denominator here is at most 2^64, so this exact comparison cannot overflow.
    quotient
        + u128::from(
            2 * remainder > denominator || (2 * remainder == denominator && quotient & 1 != 0),
        )
}

Used by 22 functions.

decimal_pair · 56 lines · calc-func/src/ported/complex_decimal.rs on GitHub
/// A decimal pair for |n| after scaling to 15 digits. For k = 14-floor(log10(|n|)),
/// the current candidate is RN64(|n| * RN64(10^k)) if k>=0, otherwise
/// RN64(|n| / RN64(10^-k)), followed by integer rounding with ties away.
/// RN64 is nearest-even rounding to 64 binary significand bits, with an unbounded exponent.
/// Multiplication by a rounded reciprocal is observably different from division.
pub(super) fn decimal_pair(n: f64) -> (u128, i32) {
    debug_assert!(n.is_finite() && n != 0.0);
    // Thirty decimal places safely identify the decade of a binary64 value, including
    // machine neighbors of powers of ten. Coefficient rounding uses integer arithmetic.
    let text = format!("{:.30e}", n.abs());
    let decimal_exponent: i32 = text
        .split_once('e')
        .expect("exponent form")
        .1
        .parse()
        .expect("exponent");
    let k = 14 - decimal_exponent;
    let bits = n.abs().to_bits();
    let encoded_exponent = ((bits >> 52) & 0x7ff) as i32;
    let fraction = bits & ((1_u64 << 52) - 1);
    let (mantissa, exponent) = if encoded_exponent == 0 {
        (fraction as u128, -1074)
    } else {
        (
            (fraction | (1_u64 << 52)) as u128,
            encoded_exponent - 1023 - 52,
        )
    };
    let (power, power_exponent) = powers::POWERS[k.unsigned_abs() as usize];
    let (scaled, scaled_exponent) = if k >= 0 {
        let product = mantissa * power as u128;
        let shift = (128 - product.leading_zeros()).saturating_sub(64);
        (
            nearest_even(product, 1_u128 << shift),
            exponent + power_exponent as i32 + shift as i32,
        )
    } else {
        // Large values have a 53-bit significand. Relative to a normalized 64-bit power,
        // its quotient's binary exponent is -11 or -12. Either numerator fits in u128.
        let shift = if mantissa << 11 >= power as u128 {
            74
        } else {
            75
        };
        (
            nearest_even(mantissa << shift, power as u128),
            exponent - power_exponent as i32 - shift,
        )
    };
    // The scaled value is between 10^14 and 10^15 (allowing a rounding carry), hence its
    // 64-bit coefficient has a negative binary exponent. Round its exact dyadic value.
    debug_assert!((-64..0).contains(&scaled_exponent));
    let denominator_shift = -scaled_exponent as u32;
    let integer = (scaled + (1_u128 << (denominator_shift - 1))) >> denominator_shift;
    (integer, -k)
}

Used by 22 functions.