#[inline]
const fn mul128_u32(lowbits: u64, d: u32) -> u64 {
(lowbits as u128 * d as u128 >> 64) as u64
}
#[inline]
const fn mul128_u64(lowbits: u128, d: u64) -> u64 {
let mut bottom_half = (lowbits & 0xFFFFFFFFFFFFFFFF) * d as u128;
bottom_half >>= 64;
let top_half = (lowbits >> 64) * d as u128;
let both_halves = bottom_half + top_half;
(both_halves >> 64) as u64
}
#[inline]
const fn compute_m_u32(d: u32) -> u64 {
(0xFFFFFFFFFFFFFFFF / d as u64) + 1
}
#[inline]
const fn fastmod_u32(a: u32, m: u64, d: u32) -> u32 {
let lowbits = m.wrapping_mul(a as u64);
mul128_u32(lowbits, d) as u32
}
#[inline]
const fn fastdiv_u32(a: u32, m: u64) -> u32 {
mul128_u32(m, a) as u32
}
#[inline]
const fn is_divisible_u32(n: u32, m: u64) -> bool {
(n as u64).wrapping_mul(m) <= m - 1
}
#[inline]
const fn compute_m_u64(d: u64) -> u128 {
(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF / d as u128) + 1
}
#[inline]
const fn fastmod_u64(a: u64, m: u128, d: u64) -> u64 {
let lowbits = m.wrapping_mul(a as u128);
mul128_u64(lowbits, d)
}
#[inline]
const fn fastdiv_u64(a: u64, m: u128) -> u64 {
mul128_u64(m, a)
}
#[inline]
const fn is_divisible_u64(n: u64, m: u128) -> bool {
(n as u128).wrapping_mul(m) <= m - 1
}
pub trait FastDiv: Copy {
type PrecomputedDiv: Copy;
fn precompute_div(self) -> Self::PrecomputedDiv;
fn fast_div(self, precomputed: Self::PrecomputedDiv) -> Self;
fn fast_mod(self, precomputed: Self::PrecomputedDiv, d: Self) -> Self;
fn is_multiple_of(self, precomputed: Self::PrecomputedDiv) -> bool;
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct PrecomputedDivU32 {
m: u64,
}
#[derive(Clone, Copy, Eq, PartialEq)]
pub struct PrecomputedDivU64 {
m: u128,
}
impl FastDiv for u32 {
type PrecomputedDiv = PrecomputedDivU32;
#[inline]
fn precompute_div(self) -> Self::PrecomputedDiv {
assert!(self > 1);
Self::PrecomputedDiv {
m: compute_m_u32(self),
}
}
#[inline]
fn fast_div(self, precomputed: Self::PrecomputedDiv) -> Self {
fastdiv_u32(self, precomputed.m)
}
#[inline]
fn fast_mod(self, precomputed: Self::PrecomputedDiv, d: Self) -> Self {
fastmod_u32(self, precomputed.m, d)
}
#[inline]
fn is_multiple_of(self, precomputed: Self::PrecomputedDiv) -> bool {
is_divisible_u32(self, precomputed.m)
}
}
impl FastDiv for u64 {
type PrecomputedDiv = PrecomputedDivU64;
#[inline]
fn precompute_div(self) -> Self::PrecomputedDiv {
assert!(self > 1);
Self::PrecomputedDiv {
m: compute_m_u64(self),
}
}
#[inline]
fn fast_div(self, precomputed: Self::PrecomputedDiv) -> Self {
fastdiv_u64(self, precomputed.m)
}
#[inline]
fn fast_mod(self, precomputed: Self::PrecomputedDiv, d: Self) -> Self {
fastmod_u64(self, precomputed.m, d)
}
#[inline]
fn is_multiple_of(self, precomputed: Self::PrecomputedDiv) -> bool {
is_divisible_u64(self, precomputed.m)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn div_u32() {
let n: u32 = 1000;
for j in 2..n {
let p = j.precompute_div();
for i in 0..n {
assert_eq!(i.fast_mod(p, j), i % j);
assert_eq!(i.fast_div(p), i / j);
assert_eq!(i.is_multiple_of(p), i % j == 0);
}
}
}
#[test]
fn div_u64() {
let n: u32 = 1000;
for j in 2..n {
let p = j.precompute_div();
for i in 0..n {
assert_eq!(i.fast_mod(p, j), i % j);
assert_eq!(i.fast_div(p), i / j);
assert_eq!(i.is_multiple_of(p), i % j == 0);
}
}
}
}