use crate::biguint::ops::add_assign;
use crate::biguint::ops::sub_assign;
use crate::errors::DivisionError;
use crate::traits::Digit;
use crate::traits::DivisionResult;
use crate::traits::DoubleDigit;
use std::cmp::Ordering;
use crate::BigUint;
mod burnikel_ziegler;
mod multiplication_helper;
pub(crate) mod newton_raphson;
pub(crate) fn div<T: Digit>(
n: &BigUint<T>,
d: &BigUint<T>,
) -> DivisionResult<(BigUint<T>, BigUint<T>)> {
match d.val.len() {
0 => Err(DivisionError::DivisionByZero),
1 => {
if d.val[0] == T::ZERO {
return Err(DivisionError::DivisionByZero);
}
let mut q = vec![T::ZERO; n.val.len()];
let r = schoolbook_div_single_digit(&n.val, d.val[0], &mut q)?;
Ok((q.into(), BigUint::new(r)))
}
_ => {
burnikel_ziegler::rem_div(n, d)
}
}
}
#[allow(unused)]
fn schoolbook_div<T: Digit>(n: &[T], d: &[T], q: &mut [T], r: &mut [T]) -> DivisionResult<()> {
debug_assert!(n.len() >= d.len());
debug_assert!(r.len() == d.len());
r.fill(T::ZERO);
q.fill(T::ZERO);
let mut p = vec![T::ZERO; d.len() + 1]; let mut shifted_d = BigUint::from(d.to_vec()) << T::NB_BITS;
for (idx, digit) in n.iter().enumerate().rev() {
let r_last_digit = r[d.len() - 1];
r.copy_within(0..d.len() - 1, 1);
r[0] = *digit;
let quotient: T = match ord(&r, r_last_digit, d) {
Ordering::Less => continue,
Ordering::Equal => {
r.fill(T::ZERO);
T::ONE
}
Ordering::Greater => {
let mut quotient = T::ZERO;
p.fill(T::ZERO);
for bit in (0..T::NB_BITS).rev() {
shifted_d >>= 1;
add_assign(&mut p, &shifted_d.val);
match ord(&r, r_last_digit, &p) {
Ordering::Less => {
sub_assign(&mut p, &shifted_d.val);
}
_ => {
quotient |= T::ONE << bit;
}
};
}
shifted_d <<= T::NB_BITS;
sub_assign(r, &p[..d.len()]);
quotient
}
};
let _ = add_assign(&mut q[idx..], &[quotient]);
}
Ok(())
}
fn ord<T: Digit>(r: &[T], r_last_digit: T, d: &[T]) -> Ordering {
match d.len() - r.len() {
0 => {
if r_last_digit > T::ZERO {
Ordering::Greater
} else {
crate::biguint::ord(r, d)
}
}
1 => {
let msb_ord = r_last_digit.cmp(&d[d.len() - 1]);
if msb_ord != Ordering::Equal {
msb_ord
} else {
crate::biguint::ord(r, &d[..d.len() - 1])
}
}
_ => unreachable!(),
}
}
fn schoolbook_div_single_digit<T: Digit>(n: &[T], d: T, q: &mut [T]) -> DivisionResult<T> {
let mut r = T::Double::ZERO;
let d_d = d.to_double();
for (idx, digit) in n.iter().enumerate().rev() {
r <<= T::NB_BITS;
r |= digit.to_double();
if r < d_d {
continue;
}
let quotient = (r / d_d).truncate_upper();
r %= d_d;
let _ = add_assign(&mut q[idx..], &[quotient]);
}
Ok(r.truncate_upper())
}