#![no_std]
use core::convert::TryInto;
use core::fmt::Debug;
use num_integer::Integer;
use num_traits::{PrimInt, Unsigned, WrappingShr};
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct DividerInner<T> {
magic: T,
more: u8,
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[repr(transparent)]
pub struct Divider<T: PrimInt>(DividerInner<T>);
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
#[repr(transparent)]
pub struct BranchFreeDivider<T: PrimInt>(DividerInner<T>);
impl<T> DividerInner<T> {
#[inline]
fn new(magic: T, more: u8) -> Self {
Self { magic, more }
}
}
const SHIFT_MASK_32: u8 = 0x1F;
const SHIFT_MASK_64: u8 = 0x3F;
const ADD_MARKER: u8 = 0x40;
const NEGATIVE_DIVISOR: u8 = 0x80;
#[derive(thiserror::Error, Debug)]
pub enum DividerError {
#[error("divider must be != 0")]
Zero,
#[error("branchfree divider must be != 1")]
BranchFreeOne,
}
pub trait DividerInt: PrimInt
where
<Self::Double as TryInto<Self>>::Error: Debug,
{
const SHIFT_MASK: u8;
const BITS: u32;
const SIGNED: bool;
type Double: PrimInt + From<Self> + TryInto<Self>;
type Unsigned: PrimInt + Unsigned;
type UnsignedDouble: PrimInt + Unsigned;
#[inline]
fn mullhi(x: Self, y: Self) -> Self {
let x = Self::Double::from(x);
let y = Self::Double::from(y);
let r = x * y;
(r >> Self::BITS as usize).try_into().unwrap()
}
fn internal_gen(self, branchfree: bool) -> Result<DividerInner<Self>, DividerError>;
fn gen(self) -> Result<DividerInner<Self>, DividerError> {
self.internal_gen(false)
}
fn branchfree_gen(self) -> Result<DividerInner<Self>, DividerError> {
if Self::SIGNED {
self.internal_gen(true)
} else {
if self == Self::one() {
return Err(DividerError::BranchFreeOne);
}
let mut inner = self.internal_gen(true)?;
inner.more &= Self::SHIFT_MASK;
Ok(inner)
}
}
fn recover(denom: &DividerInner<Self>) -> Self;
fn branchfree_recover(denom: &DividerInner<Self>) -> Self;
fn unsigned_div_by(self, denom: &Divider<Self>) -> Self {
let numer = self;
let magic = denom.0.magic;
let more = denom.0.more;
if magic.is_zero() {
numer.shr(more as usize)
} else {
let q = Self::mullhi(magic, numer);
if (more & ADD_MARKER) != 0 {
let t = ((numer - q) >> 1) + q;
t.shr((more & Self::SHIFT_MASK) as usize)
} else {
q.shr(more as usize)
}
}
}
fn unsigned_branchfree_div_by(self, denom: &BranchFreeDivider<Self>) -> Self
where
Self: WrappingShr,
{
let numer = self;
let q = Self::mullhi(denom.0.magic, numer);
let t = ((numer - q) >> 1) + q;
t.wrapping_shr(denom.0.more as u32)
}
}
impl DividerInt for u32 {
const SHIFT_MASK: u8 = SHIFT_MASK_32;
const BITS: u32 = 32;
const SIGNED: bool = false;
type Double = u64;
type Unsigned = Self;
type UnsignedDouble = Self::Double;
fn internal_gen(self, branchfree: bool) -> Result<DividerInner<Self>, DividerError> {
let d = self;
if d == 0 {
return Err(DividerError::Zero);
}
let floor_log_2_d = (Self::BITS - 1) - d.leading_zeros();
Ok(if (d & (d - 1)) == 0 {
DividerInner::new(0, (floor_log_2_d - u32::from(branchfree)) as u8)
} else {
let (proposed_m, rem) = (1u64 << (floor_log_2_d + 32)).div_rem(&(d as u64));
let mut proposed_m = proposed_m as u32;
let rem = rem as u32;
assert!(rem > 0 && rem < d);
let e = d - rem;
let more = if !branchfree && (e < (1 << floor_log_2_d)) {
floor_log_2_d as u8
} else {
proposed_m = proposed_m.wrapping_add(proposed_m);
let twice_rem = rem.wrapping_add(rem);
if twice_rem >= d || twice_rem < rem {
proposed_m += 1;
}
(floor_log_2_d as u8) | ADD_MARKER
};
DividerInner::new(1 + proposed_m, more)
})
}
fn recover(denom: &DividerInner<Self>) -> Self {
let more = denom.more;
let shift = more & Self::SHIFT_MASK;
if 0 == denom.magic {
1 << shift
} else if 0 == (more & ADD_MARKER) {
let dividend: Self::Double = 1 << (shift as u32 + Self::BITS);
1 + (dividend / denom.magic as Self::Double) as Self
} else {
let half_n: Self::Double = 1 << (32 + shift);
let d = (1 << 32) | denom.magic as Self::Double;
let (half_q, rem) = half_n.div_rem(&d);
let half_q = half_q as Self;
let full_q = half_q + half_q + Self::from((rem << 1) >= d);
full_q + 1
}
}
fn branchfree_recover(denom: &DividerInner<Self>) -> Self {
let more = denom.more;
let shift = more & Self::SHIFT_MASK;
if 0 == denom.magic {
1 << (shift + 1)
} else {
let half_n: Self::Double = 1 << (Self::BITS + shift as u32);
let d = (1 << Self::BITS) | denom.magic as Self::Double;
let (half_q, rem) = half_n.div_rem(&d);
let half_q = half_q as Self;
let full_q = half_q + half_q + Self::from((rem << 1) >= d);
full_q + 1
}
}
}
impl DividerInt for i32 {
const SHIFT_MASK: u8 = SHIFT_MASK_32;
const BITS: u32 = 32;
const SIGNED: bool = true;
type Double = i64;
type Unsigned = u32;
type UnsignedDouble = u64;
fn internal_gen(self, branchfree: bool) -> Result<DividerInner<Self>, DividerError> {
let d = self;
if d == 0 {
return Err(DividerError::Zero);
}
let abs_d = (if d < 0 { d.wrapping_neg() } else { d }) as Self::Unsigned;
let floor_log_2_d = (Self::BITS - 1) - abs_d.leading_zeros();
Ok(if (abs_d & (abs_d - 1)) == 0 {
DividerInner::new(
0,
floor_log_2_d as u8 | if d < 0 { NEGATIVE_DIVISOR } else { 0 },
)
} else {
assert!(floor_log_2_d >= 1);
let (proposed_m, rem) =
(1u64 << (floor_log_2_d - 1 + Self::BITS)).div_rem(&(abs_d as u64));
let mut proposed_m = proposed_m as Self::Unsigned;
let rem = rem as Self::Unsigned;
let e = abs_d - rem;
let mut more = if !branchfree && e < (1 << floor_log_2_d) {
(floor_log_2_d - 1) as u8
} else {
proposed_m = proposed_m.wrapping_add(proposed_m);
let twice_rem = rem.wrapping_add(rem);
if twice_rem >= abs_d || twice_rem < rem {
proposed_m += 1;
}
floor_log_2_d as u8 | ADD_MARKER
};
proposed_m += 1;
let mut magic = proposed_m as Self;
if d < 0 {
more |= NEGATIVE_DIVISOR;
if !branchfree {
magic = -magic;
}
}
DividerInner::new(magic, more)
})
}
fn recover(denom: &DividerInner<Self>) -> Self {
let more = denom.more;
let shift = more & Self::SHIFT_MASK;
if 0 == denom.magic {
let mut abs_d: Self = 1 << shift;
if 0 != (more & NEGATIVE_DIVISOR) {
abs_d = abs_d.wrapping_neg();
}
abs_d
} else {
let negative_divisor = 0 != (more & NEGATIVE_DIVISOR);
let magic_was_negated = if 0 != (more & ADD_MARKER) {
denom.magic > 0
} else {
denom.magic < 0
};
let result = if denom.magic == 0 {
1 << shift
} else {
let d = (if magic_was_negated {
-denom.magic
} else {
denom.magic
}) as Self::Unsigned;
let n = 1u64 << (32 + shift); let q = (n / d as u64) as Self::Unsigned;
q as Self + 1
};
if negative_divisor {
-result
} else {
result
}
}
}
#[inline]
fn branchfree_recover(denom: &DividerInner<Self>) -> Self {
Self::recover(denom)
}
}
impl DividerInt for u64 {
const SHIFT_MASK: u8 = SHIFT_MASK_64;
const BITS: u32 = 64;
const SIGNED: bool = false;
type Double = u128;
type Unsigned = Self;
type UnsignedDouble = Self::Double;
fn internal_gen(self, branchfree: bool) -> Result<DividerInner<Self>, DividerError> {
let d = self;
if d == 0 {
return Err(DividerError::Zero);
}
let floor_log_2_d: u32 = 63 - d.leading_zeros();
Ok(if (d & (d - 1)) == 0 {
DividerInner::new(0, (floor_log_2_d - u32::from(branchfree)) as u8)
} else {
let (proposed_m, rem) = (1u128 << (floor_log_2_d + 64)).div_rem(&(d as u128));
let mut proposed_m = proposed_m as u64;
let rem = rem as u64;
assert!(rem > 0 && rem < d);
let e = d - rem;
let more = if !branchfree && e < (1 << floor_log_2_d) {
floor_log_2_d as u8
} else {
proposed_m = proposed_m.wrapping_add(proposed_m);
let twice_rem = rem.wrapping_add(rem);
if twice_rem >= d || twice_rem < rem {
proposed_m += 1;
}
(floor_log_2_d as u8) | ADD_MARKER
};
DividerInner::new(1 + proposed_m, more)
})
}
fn recover(denom: &DividerInner<Self>) -> Self {
let more = denom.more;
let shift = more & Self::SHIFT_MASK;
if 0 == denom.magic {
1 << shift
} else if 0 == (more & ADD_MARKER) {
let dividend = 1u128 << (shift + 64);
1 + (dividend / denom.magic as u128) as u64
} else {
let half_n = 1u128 << (shift + 64);
let d = (1 << 64) | denom.magic as u128;
let (half_q, r) = half_n.div_rem(&d);
let half_q = half_q as u64;
let dr = r.wrapping_add(r);
let dr_exceeds_d = dr > d;
let full_q = half_q + half_q + u64::from(dr_exceeds_d);
full_q + 1
}
}
fn branchfree_recover(denom: &DividerInner<Self>) -> Self {
let more = denom.more;
let shift = more & Self::SHIFT_MASK;
if denom.magic == 0 {
1 << (shift + 1)
} else {
let half_n = 1u128 << (shift + 64);
let d = (1 << 64) + denom.magic as u128;
let (half_q, r) = half_n.div_rem(&d);
let half_q = half_q as u64;
let dr = r.wrapping_add(r);
let dr_exceeds_d = dr > d;
let full_q = half_q + half_q + u64::from(dr_exceeds_d);
full_q + 1
}
}
}
impl DividerInt for i64 {
const SHIFT_MASK: u8 = SHIFT_MASK_64;
const BITS: u32 = 64;
const SIGNED: bool = true;
type Double = i128;
type Unsigned = u64;
type UnsignedDouble = u128;
fn internal_gen(self, branchfree: bool) -> Result<DividerInner<Self>, DividerError> {
let d = self;
if d == 0 {
return Err(DividerError::Zero);
}
let abs_d = (if d < 0 { d.wrapping_neg() } else { d }) as Self::Unsigned;
let floor_log_2_d = (Self::BITS - 1) - abs_d.leading_zeros();
Ok(if (abs_d & (abs_d - 1)) == 0 {
DividerInner::new(
0,
floor_log_2_d as u8 | if d < 0 { NEGATIVE_DIVISOR } else { 0 },
)
} else {
assert!(floor_log_2_d >= 1);
let (proposed_m, rem) =
(1u128 << (floor_log_2_d - 1 + Self::BITS)).div_rem(&(abs_d as u128));
let mut proposed_m = proposed_m as Self::Unsigned;
let rem = rem as Self::Unsigned;
let e = abs_d - rem;
let mut more = if !branchfree && e < (1 << floor_log_2_d) {
(floor_log_2_d - 1) as u8
} else {
proposed_m = proposed_m.wrapping_add(proposed_m);
let twice_rem = rem.wrapping_add(rem);
if twice_rem >= abs_d || twice_rem < rem {
proposed_m += 1;
}
floor_log_2_d as u8 | ADD_MARKER
};
proposed_m += 1;
let mut magic = proposed_m as Self;
if d < 0 {
more |= NEGATIVE_DIVISOR;
if !branchfree {
magic = -magic;
}
}
DividerInner::new(magic, more)
})
}
fn recover(denom: &DividerInner<Self>) -> Self {
let more = denom.more;
let shift = more & Self::SHIFT_MASK;
if 0 == denom.magic {
let mut abs_d = 1i64 << shift;
if 0 != (more & NEGATIVE_DIVISOR) {
abs_d = abs_d.wrapping_neg();
}
abs_d
} else {
let negative_divisor = 0 != (more & NEGATIVE_DIVISOR);
let magic_was_negated = if 0 != (more & ADD_MARKER) {
denom.magic > 0
} else {
denom.magic < 0
};
let d = if magic_was_negated {
-denom.magic
} else {
denom.magic
} as Self::Unsigned;
let n = 1u128 << (shift as u32 + Self::BITS);
let q = (n / d as u128) as u64;
let mut result = (q + 1) as Self;
if negative_divisor {
result = -result;
}
result
}
}
#[inline]
fn branchfree_recover(denom: &DividerInner<Self>) -> Self {
Self::recover(denom)
}
}
impl<T: DividerInt> From<T> for Divider<T> {
fn from(d: T) -> Self {
Self::new(d).unwrap()
}
}
impl<T: DividerInt> Divider<T> {
pub fn new(d: T) -> Result<Self, DividerError> {
d.gen().map(Self)
}
pub fn recover(&self) -> T {
T::recover(&self.0)
}
}
impl<T: DividerInt> From<T> for BranchFreeDivider<T> {
fn from(d: T) -> Self {
Self::new(d).unwrap()
}
}
impl<T: DividerInt> BranchFreeDivider<T> {
pub fn new(d: T) -> Result<Self, DividerError> {
d.branchfree_gen().map(Self)
}
pub fn recover(&self) -> T {
T::branchfree_recover(&self.0)
}
}
impl core::ops::Div<&Divider<Self>> for u32 {
type Output = Self;
#[inline]
fn div(self, denom: &Divider<Self>) -> Self::Output {
self.unsigned_div_by(denom)
}
}
impl core::ops::Div<&BranchFreeDivider<Self>> for u32 {
type Output = Self;
#[inline]
fn div(self, denom: &BranchFreeDivider<Self>) -> Self::Output {
self.unsigned_branchfree_div_by(denom)
}
}
impl core::ops::Div<&Divider<Self>> for i32 {
type Output = Self;
#[inline]
fn div(self, denom: &Divider<Self>) -> Self::Output {
let numer = self;
let more = denom.0.more;
let shift = more & Self::SHIFT_MASK;
if 0 == denom.0.magic {
let sign = (more as i8 >> 7) as u32;
let mask = (1u32 << shift) - 1;
let uq = (numer as u32).wrapping_add((numer >> 31) as u32 & mask);
let mut q = uq as Self;
q >>= shift;
q = (q as u32 ^ sign).wrapping_sub(sign) as Self;
q
} else {
let mut uq = Self::mullhi(denom.0.magic, numer) as u32;
if 0 != (more & ADD_MARKER) {
let sign = (more as i8 >> 7) as Self;
uq = uq.wrapping_add(((numer as u32) ^ (sign as u32)).wrapping_sub(sign as u32));
}
let mut q = uq as Self;
q >>= shift;
q += Self::from(q < 0);
q
}
}
}
impl core::ops::Div<&BranchFreeDivider<Self>> for i32 {
type Output = Self;
#[inline]
fn div(self, denom: &BranchFreeDivider<Self>) -> Self::Output {
let numer = self;
let more = denom.0.more;
let shift = more & Self::SHIFT_MASK;
let sign = (more as i8 >> 7) as Self;
let magic = denom.0.magic;
let mut q = Self::mullhi(magic, numer);
q += numer;
let is_power_of_2 = u32::from(magic == 0);
let q_sign = (q >> 31) as u32;
q += (q_sign & ((1 << shift) - is_power_of_2)) as Self;
q >>= shift;
q = (q ^ sign).wrapping_sub(sign);
q
}
}
impl core::ops::Div<&Divider<Self>> for u64 {
type Output = Self;
#[inline]
fn div(self, denom: &Divider<Self>) -> Self::Output {
self.unsigned_div_by(denom)
}
}
impl core::ops::Div<&BranchFreeDivider<Self>> for u64 {
type Output = Self;
#[inline]
fn div(self, denom: &BranchFreeDivider<Self>) -> Self::Output {
self.unsigned_branchfree_div_by(denom)
}
}
impl core::ops::Div<&Divider<Self>> for i64 {
type Output = Self;
#[inline]
fn div(self, denom: &Divider<Self>) -> Self::Output {
let numer = self;
let more = denom.0.more;
let shift = more & Self::SHIFT_MASK;
if 0 == denom.0.magic {
let sign = (more as i8 >> 7) as u64;
let mask = (1u64 << shift) - 1;
let uq = (numer as u64).wrapping_add((numer >> 63) as u64 & mask);
let mut q = uq as Self;
q >>= shift;
q = (q as u64 ^ sign).wrapping_sub(sign) as Self;
q
} else {
let mut uq = Self::mullhi(denom.0.magic, numer) as u64;
if 0 != (more & ADD_MARKER) {
let sign = (more as i8 >> 7) as Self;
uq = uq.wrapping_add(((numer as u64) ^ (sign as u64)).wrapping_sub(sign as u64));
}
let mut q = uq as Self;
q >>= shift;
q += Self::from(q < 0);
q
}
}
}
impl core::ops::Div<&BranchFreeDivider<Self>> for i64 {
type Output = Self;
#[inline]
fn div(self, denom: &BranchFreeDivider<Self>) -> Self::Output {
let numer = self;
let more = denom.0.more;
let shift = more & Self::SHIFT_MASK;
let sign = (more as i8 >> 7) as Self;
let magic = denom.0.magic;
let mut q = Self::mullhi(magic, numer);
q += numer;
let is_power_of_2 = u64::from(magic == 0);
let q_sign = (q >> 63) as u64;
q += (q_sign & ((1 << shift) - is_power_of_2)) as Self;
q >>= shift;
q = (q ^ sign).wrapping_sub(sign);
q
}
}