Functional Weave
Code in Rust

math.round-div@1.0.0

impl/rust.rs

1,603 bytes · the Rust implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

use super::funejson::Value;  ← the fune runtime: the JSON value the test vectors use; fune build keeps it only where a signature takes one

/// Divide two integers, rounding according to `mode`.
///
/// Money is held in minor units (pence, cents) as integers. Every rate,
/// discount and tax calculation eventually needs to divide, and that division
/// is where rounding policy lives. Making it explicit here means a system can
/// state its policy once instead of scattering `round()` through a codebase.
///
/// # Panics
/// Panics if `denominator` is zero, or the mode is not recognised.
pub fn round_div(numerator: i64, denominator: i64, mode: &str) -> i64 {
    if denominator == 0 {
        panic!("denominator must not be zero");
    }

    let negative = (numerator < 0) != (denominator < 0);
    let n = numerator.unsigned_abs() as i128;
    let d = denominator.unsigned_abs() as i128;

    let mut quotient = n / d;
    let remainder = n % d;
    let twice = remainder * 2;

    match mode {
        "down" => {}
        "up" => {
            if remainder > 0 {
                quotient += 1;
            }
        }
        "half-even" => {
            if twice > d || (twice == d && quotient % 2 == 1) {
                quotient += 1;
            }
        }
        "half-up" => {
            if twice >= d {
                quotient += 1;
            }
        }
        other => panic!("unknown rounding mode \"{}\"", other),
    }

    let result = quotient as i64;
    if negative {
        -result
    } else {
        result
    }
}

pub fn fune_vector(args: &[Value]) -> Value {
    Value::Int(round_div(
        args[0].as_i64(),
        args[1].as_i64(),
        args[2].as_str(),
    ))
}