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
use super::math_big_integer::{parse_big_integer, BigInt}; ← from math.big-integer ^1.0.0 · built alongside by fune
/// math.round-div, for integers too big for an i64.
///
/// An exact product such as distance x gallon size x price per litre easily
/// passes 2^63, where `round_div` would overflow. The rounding rules are the
/// same as math.round-div's: every mode works on the magnitude and puts the
/// sign back afterwards, so -7/2 half-up is -4.
///
/// # Panics
/// Panics on a malformed number, a zero denominator or an unknown mode.
pub fn round_div_big(numerator: &str, denominator: &str, mode: &str) -> String {
let n0 = parse_big_integer(numerator);
let d0 = parse_big_integer(denominator);
if d0.is_zero() {
panic!("denominator must not be zero");
}
let negative = n0.is_negative() != d0.is_negative();
let n = n0.abs();
let d = d0.abs();
let (mut quotient, remainder) = n.div_rem(&d);
let twice = remainder.add(&remainder);
let one = BigInt::from_i64(1);
match mode {
"down" => {}
"up" => {
if !remainder.is_zero() {
quotient = quotient.add(&one);
}
}
"half-even" => {
let odd = !quotient.rem(&BigInt::from_i64(2)).is_zero();
if twice > d || (twice == d && odd) {
quotient = quotient.add(&one);
}
}
"half-up" => {
if twice >= d {
quotient = quotient.add(&one);
}
}
other => panic!("unknown rounding mode \"{}\"", other),
}
if negative && !quotient.is_zero() {
quotient = quotient.neg();
}
quotient.to_string()
}
pub fn fune_vector(args: &[Value]) -> Value {
for (i, name) in [(0usize, "numerator"), (1usize, "denominator")] {
if !matches!(args[i], Value::Str(_)) {
panic!("not a whole number in decimal: {} must be a string", name);
}
}
Value::str(&round_div_big(args[0].as_str(), args[1].as_str(), args[2].as_str()))
}