use super::funejson::Value; /// 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(), )) }