pub trait FloorDivMod: Sized {
fn wrapping_floor_div_mod(self, other: Self) -> (Self, Self);
}
macro_rules! impl_float_div_mod {
($T:ty) => {
impl FloorDivMod for $T {
#[inline]
fn wrapping_floor_div_mod(self, other: Self) -> (Self, Self) {
let div = (self / other).floor();
let mod_ = self - other * div;
(div, mod_)
}
}
};
}
macro_rules! impl_unsigned_div_mod {
($T:ty) => {
impl FloorDivMod for $T {
#[inline]
fn wrapping_floor_div_mod(self, other: Self) -> (Self, Self) {
(self / other, self % other)
}
}
};
}
macro_rules! impl_signed_div_mod {
($T:ty) => {
impl FloorDivMod for $T {
#[inline]
fn wrapping_floor_div_mod(self, other: Self) -> (Self, Self) {
if other == 0 {
return (0, 0);
}
let mut div = self.wrapping_div(other);
let mut mod_ = self.wrapping_rem(other);
if mod_ != 0 && (self < 0) != (other < 0) {
div -= 1;
mod_ += other;
}
(div, mod_)
}
}
};
}
impl_unsigned_div_mod!(u8);
impl_unsigned_div_mod!(u16);
impl_unsigned_div_mod!(u32);
impl_unsigned_div_mod!(u64);
impl_unsigned_div_mod!(u128);
impl_unsigned_div_mod!(usize);
impl_signed_div_mod!(i8);
impl_signed_div_mod!(i16);
impl_signed_div_mod!(i32);
impl_signed_div_mod!(i64);
impl_signed_div_mod!(i128);
impl_signed_div_mod!(isize);
impl_float_div_mod!(f32);
impl_float_div_mod!(f64);
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_signed_wrapping_div_mod() {
for lhs in i8::MIN..=i8::MAX {
for rhs in i8::MIN..=i8::MAX {
let ans = if rhs != 0 {
let fdiv = (lhs as f64 / rhs as f64).floor();
let fmod = lhs as f64 - rhs as f64 * fdiv;
((fdiv as i32) as i8, (fmod as i32) as i8)
} else {
(0, 0)
};
assert_eq!(lhs.wrapping_floor_div_mod(rhs), ans);
}
}
}
}