use crate::{
add,
arch::word::{SignedWord, Word},
div,
fast_divide::FastDivideNormalized,
memory::Memory,
mul,
sign::Sign::*,
};
use alloc::alloc::Layout;
use static_assertions::const_assert;
pub(crate) fn memory_requirement_exact(lhs_len: usize, rhs_len: usize) -> Layout {
assert!(lhs_len >= rhs_len);
let smaller_len = (rhs_len / 2).min(lhs_len - rhs_len);
mul::memory_requirement_up_to(rhs_len, smaller_len)
}
#[must_use]
pub(crate) fn div_rem_in_place(
lhs: &mut [Word],
rhs: &[Word],
fast_div_rhs_top: FastDivideNormalized,
memory: &mut Memory,
) -> bool {
assert!(lhs.len() > rhs.len() + div::MAX_LEN_SIMPLE && rhs.len() > div::MAX_LEN_SIMPLE);
let mut overflow = false;
let n = rhs.len();
let mut m = lhs.len();
assert!(n > div::MAX_LEN_SIMPLE && m >= n);
while m >= 2 * n {
let o = div_rem_in_place_same_len(&mut lhs[m - 2 * n..m], rhs, fast_div_rhs_top, memory);
if o {
assert!(m == lhs.len());
overflow = true;
}
m -= n;
}
if m > n {
let o = div_rem_in_place_small_quotient(&mut lhs[..m], rhs, fast_div_rhs_top, memory);
if o {
assert!(m == lhs.len());
overflow = true;
}
}
overflow
}
#[must_use]
fn div_rem_in_place_same_len(
lhs: &mut [Word],
rhs: &[Word],
fast_div_rhs_top: FastDivideNormalized,
memory: &mut Memory,
) -> bool {
let n = rhs.len();
assert!(n > div::MAX_LEN_SIMPLE && lhs.len() == 2 * n);
const_assert!(div::MAX_LEN_SIMPLE >= 3);
let n_lo = n / 2;
let overflow = div_rem_in_place_small_quotient(&mut lhs[n_lo..], rhs, fast_div_rhs_top, memory);
let overflow_lo =
div_rem_in_place_small_quotient(&mut lhs[..n + n_lo], rhs, fast_div_rhs_top, memory);
assert!(!overflow_lo);
overflow
}
#[must_use]
fn div_rem_in_place_small_quotient(
lhs: &mut [Word],
rhs: &[Word],
fast_div_rhs_top: FastDivideNormalized,
memory: &mut Memory,
) -> bool {
let n = rhs.len();
assert!(n >= 2 && lhs.len() >= n);
let m = lhs.len() - n;
assert!(m < n);
if m <= div::MAX_LEN_SIMPLE {
return div::simple::div_rem_in_place(lhs, rhs, fast_div_rhs_top);
}
let mut q_overflow: SignedWord =
div_rem_in_place_same_len(&mut lhs[n - m..], &rhs[n - m..], fast_div_rhs_top, memory)
.into();
let (rem, q) = lhs.split_at_mut(n);
let mut rem_overflow: SignedWord = mul::add_signed_mul(rem, Negative, q, &rhs[..n - m], memory);
if q_overflow != 0 {
rem_overflow -= SignedWord::from(add::sub_same_len_in_place(&mut rem[m..], &rhs[..n - m]));
}
while rem_overflow < 0 {
rem_overflow += SignedWord::from(add::add_same_len_in_place(rem, rhs));
q_overflow -= SignedWord::from(add::sub_one_in_place(q));
}
assert!(rem_overflow == 0 && (0..=1).contains(&q_overflow));
q_overflow != 0
}