use super::HeaplessBigInt;
use crate::MachineWord;
use const_num_traits::{CarryingMul, Nct, One, Zero};
fn div_rem_impl<T, const CAP: usize>(
dividend: &HeaplessBigInt<T, CAP, Nct>,
divisor: &HeaplessBigInt<T, CAP, Nct>,
) -> (HeaplessBigInt<T, CAP, Nct>, HeaplessBigInt<T, CAP, Nct>)
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
use core::cmp::Ordering;
assert!(
!<HeaplessBigInt<T, CAP, Nct> as Zero>::is_zero(divisor),
"HeaplessBigInt: divide by zero"
);
let work_len = core::cmp::max(dividend.len(), divisor.len());
match dividend.cmp(divisor) {
Ordering::Less => {
return (
<HeaplessBigInt<T, CAP, Nct> as Zero>::zero().widened(work_len),
dividend.widened(work_len),
);
}
Ordering::Equal => {
return (
<HeaplessBigInt<T, CAP, Nct> as One>::one().widened(work_len),
<HeaplessBigInt<T, CAP, Nct> as Zero>::zero().widened(work_len),
);
}
Ordering::Greater => {}
}
let d_bits = dividend.bit_length();
let dv_bits = divisor.bit_length();
let mut shift = d_bits - dv_bits;
let mut rem = dividend.widened(work_len);
let wide_divisor = divisor.widened(work_len);
let one = <HeaplessBigInt<T, CAP, Nct> as One>::one().widened(work_len);
let mut quotient = <HeaplessBigInt<T, CAP, Nct> as Zero>::zero().widened(work_len);
let mut shifted = wide_divisor << shift;
let mut bit = one << shift;
loop {
if rem >= shifted {
rem = rem.wrapping_sub(&shifted);
quotient = quotient.wrapping_add(&bit);
}
if shift == 0 {
break;
}
shifted >>= 1;
bit >>= 1;
shift -= 1;
}
(quotient, rem)
}
macro_rules! div_impls {
($lhs:ty, $rhs:ty, $out:ty) => {
impl<T, const CAP: usize> core::ops::Div<$rhs> for $lhs
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
type Output = $out;
fn div(self, other: $rhs) -> Self::Output {
div_rem_impl::<T, CAP>(&self, &other).0
}
}
impl<T, const CAP: usize> core::ops::Rem<$rhs> for $lhs
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
type Output = $out;
fn rem(self, other: $rhs) -> Self::Output {
div_rem_impl::<T, CAP>(&self, &other).1
}
}
};
}
div_impls!(
HeaplessBigInt<T, CAP, Nct>,
HeaplessBigInt<T, CAP, Nct>,
HeaplessBigInt<T, CAP, Nct>
);
div_impls!(
HeaplessBigInt<T, CAP, Nct>,
&HeaplessBigInt<T, CAP, Nct>,
HeaplessBigInt<T, CAP, Nct>
);
div_impls!(
&HeaplessBigInt<T, CAP, Nct>,
HeaplessBigInt<T, CAP, Nct>,
HeaplessBigInt<T, CAP, Nct>
);
div_impls!(
&HeaplessBigInt<T, CAP, Nct>,
&HeaplessBigInt<T, CAP, Nct>,
HeaplessBigInt<T, CAP, Nct>
);
impl<T, const CAP: usize> core::ops::DivAssign for HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
fn div_assign(&mut self, other: Self) {
*self = div_rem_impl::<T, CAP>(self, &other).0;
}
}
impl<T, const CAP: usize> core::ops::DivAssign<&HeaplessBigInt<T, CAP, Nct>>
for HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
fn div_assign(&mut self, other: &Self) {
*self = div_rem_impl::<T, CAP>(self, other).0;
}
}
impl<T, const CAP: usize> core::ops::RemAssign for HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
fn rem_assign(&mut self, other: Self) {
*self = div_rem_impl::<T, CAP>(self, &other).1;
}
}
impl<T, const CAP: usize> core::ops::RemAssign<&HeaplessBigInt<T, CAP, Nct>>
for HeaplessBigInt<T, CAP, Nct>
where
T: MachineWord + CarryingMul<Unsigned = T, Output = T>,
{
fn rem_assign(&mut self, other: &Self) {
*self = div_rem_impl::<T, CAP>(self, other).1;
}
}