use crate::{
add,
arch::word::Word,
cmp,
fast_divide::FastDivideNormalized,
mul,
primitive::{double_word, extend_word},
};
use core::cmp::Ordering;
#[must_use]
pub(crate) fn div_rem_in_place(
lhs: &mut [Word],
rhs: &[Word],
fast_div_rhs_top: FastDivideNormalized,
) -> bool {
let n = rhs.len();
assert!(n >= 2);
let rhs0 = rhs[n - 1];
let rhs1 = rhs[n - 2];
let mut lhs_len = lhs.len();
assert!(lhs_len >= n);
let quotient_carry = cmp::cmp_same_len(&lhs[lhs_len - n..], rhs) >= Ordering::Equal;
if quotient_carry {
let overflow = add::sub_same_len_in_place(&mut lhs[lhs_len - n..], rhs);
assert!(!overflow);
}
while lhs_len > n {
let lhs0 = lhs[lhs_len - 1];
let lhs1 = lhs[lhs_len - 2];
let lhs2 = lhs[lhs_len - 3];
let lhs01 = double_word(lhs1, lhs0);
let mut q = if lhs0 < rhs0 {
let (mut q, mut r) = fast_div_rhs_top.div_rem(lhs01);
while extend_word(q) * extend_word(rhs1) > double_word(lhs2, r) {
q -= 1;
match r.checked_add(rhs0) {
None => break,
Some(r2) => r = r2,
}
}
q
} else {
Word::MAX
};
let mut borrow =
mul::sub_mul_word_same_len_in_place(&mut lhs[lhs_len - 1 - n..lhs_len - 1], q, rhs);
if borrow > lhs0 {
q -= 1;
let carry = add::add_same_len_in_place(&mut lhs[lhs_len - 1 - n..lhs_len - 1], rhs);
debug_assert!(carry);
borrow -= 1;
}
debug_assert!(borrow == lhs0);
lhs_len -= 1;
lhs[lhs_len] = q;
}
quotient_carry
}