pub fn divmod(a: f64, b: f64) -> (f64, f64) {
let mut m = a % b;
let mut div = (a - m) / b;
if m != 0.0 {
if (b < 0.0) != (m < 0.0) {
m += b;
div -= 1.0;
}
} else {
m = 0.0_f64.copysign(b);
}
let floordiv = if div != 0.0 {
let mut f = div.floor();
if div - f > 0.5 {
f += 1.0;
}
f
} else {
0.0_f64.copysign(a / b)
};
(floordiv, m)
}
pub fn rem(a: f64, b: f64) -> f64 {
divmod(a, b).1
}
pub fn floordiv(a: f64, b: f64) -> f64 {
divmod(a, b).0
}
pub fn round(x: f64, ndigits: usize) -> f64 {
if !x.is_finite() {
return x;
}
format!("{x:.ndigits$}").parse().unwrap()
}
pub fn round_int(x: f64) -> i64 {
x.round_ties_even() as i64
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn modulo_follows_python() {
assert_eq!(rem(-30.0, 360.0), 330.0);
assert_eq!(rem(370.0, 360.0), 10.0);
assert_eq!(rem(-0.0, 360.0), 0.0);
assert_eq!(rem(-1e-18, 360.0), 360.0);
}
#[test]
fn floordiv_follows_python() {
assert_eq!((1.0_f64 / 0.1).floor(), 10.0);
assert_eq!(floordiv(1.0, 0.1), 9.0);
assert_eq!(floordiv(89.99999999999999, 30.0), 2.0);
assert_eq!(floordiv(-1.0, 30.0), -1.0);
}
#[test]
fn round_follows_python() {
assert_eq!(round(0.125, 2), 0.12);
assert_eq!(round(0.375, 2), 0.38);
assert_eq!(round(2.675, 2), 2.67);
assert_eq!(round(1.0000005, 6), 1.000001);
assert_eq!(round_int(2.5), 2);
assert_eq!(round_int(3.5), 4);
}
}