use crate::{
add,
arch::word::Word,
cmp,
math::FastDivideNormalized2,
mul,
primitive::{double_word, highest_dword, split_dword},
};
#[must_use]
pub(crate) fn div_rem_in_place(
lhs: &mut [Word],
rhs: &[Word],
fast_div_rhs_top: FastDivideNormalized2,
) -> bool {
let n = rhs.len();
assert!(n >= 2);
let lhs_len = lhs.len();
assert!(lhs_len >= n);
let quotient_carry = cmp::cmp_same_len(&lhs[lhs_len - n..], rhs).is_ge();
if quotient_carry {
let overflow = add::sub_same_len_in_place(&mut lhs[lhs_len - n..], rhs);
debug_assert!(!overflow);
}
let mut rem = lhs;
while rem.len() > n {
let (lhs_top, lhs_lo) = rem.split_last_mut().unwrap();
*lhs_top = div_rem_highest_word(*lhs_top, lhs_lo, rhs, fast_div_rhs_top);
rem = lhs_lo;
}
quotient_carry
}
#[inline]
pub(crate) fn div_rem_highest_word(
lhs_top: Word,
lhs_lo: &mut [Word],
rhs: &[Word],
fast_div_rhs_top: FastDivideNormalized2,
) -> Word {
let n = rhs.len();
let (rhs_top, rhs_lo) = rhs.split_last().unwrap();
let lhs_lo_len = lhs_lo.len();
debug_assert!(lhs_lo_len >= n);
debug_assert!(lhs_top
.cmp(rhs_top)
.then(cmp::cmp_same_len(&lhs_lo[lhs_lo_len - rhs_lo.len()..], rhs_lo))
.is_le());
let (lhs2, lhs1) = split_dword(highest_dword(lhs_lo));
let lhs01 = double_word(lhs1, lhs_top);
let mut q = if lhs_top < *rhs_top {
fast_div_rhs_top.div_rem_3by2(lhs2, lhs01).0
} else {
Word::MAX
};
let mut borrow = mul::sub_mul_word_same_len_in_place(&mut lhs_lo[lhs_lo_len - n..], q, rhs);
if borrow > lhs_top {
q -= 1;
let carry = add::add_same_len_in_place(&mut lhs_lo[lhs_lo_len - n..], rhs);
debug_assert!(carry);
borrow -= 1;
}
debug_assert!(borrow == lhs_top);
q
}