pub(crate) const fn div_rem(n: u64, d: u64) -> (u64, u64) {
if d == 0 || n < d {
return (0, n);
}
let shift = d.leading_zeros() - n.leading_zeros();
let mut step = d << shift;
let mut rest = n;
let mut quotient = 0;
let mut steps = shift + 1;
while steps > 0 {
quotient <<= 1;
if rest >= step {
rest -= step;
quotient |= 1;
}
step >>= 1;
steps -= 1;
}
(quotient, rest)
}
#[cfg(test)]
mod tests {
use super::div_rem;
fn native(n: u64, d: u64) -> (u64, u64) {
(n / d, n % d)
}
#[test]
fn matches_native_division_at_the_edges() {
let divisors = [
1,
2,
3,
7,
1_000,
1_000_000,
1_000_000_000,
1 << 31,
(1 << 32) - 1,
1 << 32,
(1 << 63) - 1,
1 << 63,
u64::MAX - 1,
u64::MAX,
];
for d in divisors {
for n in [
0,
1,
d - 1,
d,
d.wrapping_add(1),
d.saturating_mul(2),
d.saturating_mul(2).saturating_sub(1),
(1 << 63) - 1,
1 << 63,
u64::MAX - 1,
u64::MAX,
] {
assert_eq!(div_rem(n, d), native(n, d), "{n} / {d}");
}
}
}
#[test]
fn a_zero_divisor_leaves_the_dividend() {
assert_eq!(div_rem(0, 0), (0, 0));
assert_eq!(div_rem(u64::MAX, 0), (0, u64::MAX));
}
proptest::proptest! {
#[test]
fn matches_native_division(n in proptest::prelude::any::<u64>(), d in 1u64..) {
proptest::prop_assert_eq!(div_rem(n, d), native(n, d));
}
#[test]
fn matches_native_division_by_short_divisors(
n in proptest::prelude::any::<u64>(),
d in 1u64..(1 << 32),
) {
proptest::prop_assert_eq!(div_rem(n, d), native(n, d));
}
}
}