use awint_internals::*;
use const_fn::const_fn;
use crate::Bits;
impl Bits {
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn digit_udivide_inplace_(&mut self, div: Digit) -> Option<Digit> {
if div == 0 {
return None
}
let mut rem = 0;
const_for!(i in {0..self.total_digits()}.rev() {
let y = unsafe {self.get_unchecked(i)};
let tmp = dd_division((y, rem), (div, 0));
rem = tmp.1.0;
*unsafe {self.get_unchecked_mut(i)} = tmp.0.0;
});
Some(rem)
}
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn digit_udivide_(&mut self, duo: &Self, div: Digit) -> Option<Digit> {
if div == 0 || self.bw() != duo.bw() {
return None
}
let mut rem = 0;
const_for!(i in {0..self.total_digits()}.rev() {
let y = unsafe {duo.get_unchecked(i)};
let tmp = dd_division((y, rem), (div, 0));
rem = tmp.1.0;
*unsafe {self.get_unchecked_mut(i)} = tmp.0.0;
});
Some(rem)
}
#[const_fn(cfg(feature = "const_support"))]
pub(crate) const unsafe fn two_possibility_algorithm(
quo: &mut Self,
rem: &mut Self,
duo: &Self,
div: &Self,
) {
debug_assert!(div.lz() > duo.lz());
debug_assert!((div.lz() - duo.lz()) < BITS);
debug_assert!((duo.sig()) >= (BITS * 2));
let i = duo.sig() - (BITS * 2);
let duo_sig_dd = duo.get_double_digit(i);
let div_sig_dd = div.get_double_digit(i);
let mut small_quo = dd_division(duo_sig_dd, div_sig_dd).0 .0;
rem.copy_(div).unwrap();
let uof = rem.digit_cin_mul_(0, small_quo);
rem.rsb_(duo).unwrap();
if (uof != 0) || rem.msb() {
rem.add_(div).unwrap();
small_quo -= 1;
}
quo.digit_(small_quo);
}
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn udivide(quo: &mut Self, rem: &mut Self, duo: &Self, div: &Self) -> Option<()> {
quo.assert_cleared_unused_bits();
rem.assert_cleared_unused_bits();
duo.assert_cleared_unused_bits();
div.assert_cleared_unused_bits();
let w = quo.bw();
if div.is_zero() || w != rem.bw() || w != duo.bw() || w != div.bw() {
return None
}
let len = quo.total_digits();
let mut duo_lz = duo.lz();
let div_lz = div.lz();
if div_lz <= duo_lz {
if duo.uge(div).unwrap() {
quo.uone_();
rem.copy_(duo).unwrap();
rem.sub_(div).unwrap();
} else {
quo.zero_();
rem.copy_(duo).unwrap();
}
return Some(())
}
if (w - duo_lz) <= BITS {
let tmp_duo = duo.to_digit();
let tmp_div = div.to_digit();
quo.digit_(tmp_duo.wrapping_div(tmp_div));
rem.digit_(tmp_duo.wrapping_rem(tmp_div));
return Some(())
}
if (w - duo_lz) <= BITS * 2 {
unsafe {
let tmp = dd_division(
(duo.first(), duo.get_unchecked(1)),
(div.first(), div.get_unchecked(1)),
);
quo.digit_(tmp.0 .0);
*quo.get_unchecked_mut(1) = tmp.0 .1;
rem.digit_(tmp.1 .0);
*rem.get_unchecked_mut(1) = tmp.1 .1;
}
return Some(())
}
if w - div_lz <= BITS {
let tmp = quo.digit_udivide_(duo, div.to_digit()).unwrap();
rem.digit_(tmp);
return Some(())
}
let lz_diff = div_lz - duo_lz;
if lz_diff < BITS {
unsafe {
Bits::two_possibility_algorithm(quo, rem, duo, div);
}
return Some(())
}
let div_extra = w - div_lz - BITS;
let div_sig_d = div.get_digit(div_extra);
let div_sig_d_add1 = widen_add(div_sig_d, 1, 0);
quo.zero_();
rem.copy_(duo).unwrap();
loop {
let duo_extra = w - duo_lz - (BITS * 2) + 1;
if div_extra < duo_extra {
let duo_sig_dd = unsafe {
let digits = digits_u(duo_extra);
let bits = extra_u(duo_extra);
if bits == 0 {
(rem.get_unchecked(digits), rem.get_unchecked(digits + 1))
} else {
let mid = rem.get_unchecked(digits + 1);
let last = if digits + 2 == len {
0
} else {
rem.get_unchecked(digits + 2)
};
(
(rem.get_unchecked(digits) >> bits) | (mid << (BITS - bits)),
(mid >> bits) | (last << (BITS - bits)),
)
}
};
let quo_part = dd_division(duo_sig_dd, div_sig_d_add1).0 .0;
let extra_shl = duo_extra - div_extra;
let shl_bits = extra_u(extra_shl);
let shl_digits = digits_u(extra_shl);
let (carry, next) = unsafe {
if shl_bits == 0 {
let tmp = widen_add(quo.get_unchecked(shl_digits), quo_part, 0);
*quo.get_unchecked_mut(shl_digits) = tmp.0;
(tmp.1 != 0, shl_digits + 1)
} else {
let tmp0 =
widen_add(quo.get_unchecked(shl_digits), quo_part << shl_bits, 0);
*quo.get_unchecked_mut(shl_digits) = tmp0.0;
let tmp1 = widen_add(
quo.get_unchecked(shl_digits + 1),
quo_part >> (BITS - shl_bits),
tmp0.1,
);
*quo.get_unchecked_mut(shl_digits + 1) = tmp1.0;
(tmp1.1 != 0, shl_digits + 2)
}
};
unsafe {
subdigits_mut!(quo, { next..len }, subquo, {
subquo.inc_(carry);
});
}
let mut wrap_carry = 0;
let mut mul_carry = 0;
let mut add_carry = 1;
unsafe {
if shl_bits == 0 {
const_for!(i in {shl_digits..len} {
let tmp1 = widen_mul_add(
div.get_unchecked(i - shl_digits),
quo_part,
mul_carry
);
mul_carry = tmp1.1;
let tmp2 = widen_add(!tmp1.0, rem.get_unchecked(i), add_carry);
add_carry = tmp2.1;
*rem.get_unchecked_mut(i) = tmp2.0;
});
} else {
const_for!(i in {shl_digits..len} {
let tmp0 = wrap_carry | (div.get_unchecked(i - shl_digits) << shl_bits);
wrap_carry = div.get_unchecked(i - shl_digits) >> (BITS - shl_bits);
let tmp1 = widen_mul_add(tmp0, quo_part, mul_carry);
mul_carry = tmp1.1;
let tmp2 = widen_add(!tmp1.0, rem.get_unchecked(i), add_carry);
add_carry = tmp2.1;
*rem.get_unchecked_mut(i) = tmp2.0;
});
}
}
} else {
let i = w - duo_lz - (BITS * 2);
let duo_sig_dd = rem.get_double_digit(i);
let div_sig_dd = div.get_double_digit(i);
let mut small_quo = dd_division(duo_sig_dd, div_sig_dd).0 .0;
let mut mul_carry = 0;
let mut add_carry = 1;
unsafe {
const_for!(i in {0..len} {
let tmp0 = widen_mul_add(div.get_unchecked(i), small_quo, mul_carry);
mul_carry = tmp0.1;
let tmp1 = widen_add(!tmp0.0, rem.get_unchecked(i), add_carry);
add_carry = tmp1.1;
*rem.get_unchecked_mut(i) = tmp1.0;
});
}
if rem.msb() {
rem.add_(div).unwrap();
small_quo -= 1;
}
let tmp = widen_add(quo.first(), small_quo, 0);
*quo.first_mut() = tmp.0;
unsafe {
subdigits_mut!(quo, { 1..len }, subquo, {
subquo.inc_(tmp.1 != 0);
});
}
return Some(())
}
duo_lz = rem.lz();
if div_lz <= duo_lz {
if div_lz == duo_lz && div.ule(rem).unwrap() {
quo.inc_(true);
rem.sub_(div).unwrap();
}
return Some(())
}
if (w - duo_lz) <= (BITS * 2) {
unsafe {
let tmp = dd_division(
(rem.first(), rem.get_unchecked(1)),
(div.first(), div.get_unchecked(1)),
);
let tmp0 = widen_add(quo.first(), tmp.0 .0, 0);
*quo.first_mut() = tmp0.0;
subdigits_mut!(quo, { 1..len }, subquo, {
subquo.inc_(tmp0.1 != 0);
});
rem.digit_(tmp.1 .0);
*rem.get_unchecked_mut(1) = tmp.1 .1;
}
return Some(())
}
}
}
#[const_fn(cfg(feature = "const_support"))]
#[must_use]
pub const fn idivide(
quo: &mut Self,
rem: &mut Self,
duo: &mut Self,
div: &mut Self,
) -> Option<()> {
let w = quo.bw();
if div.is_zero() || w != rem.bw() || w != duo.bw() || w != div.bw() {
return None
}
let duo_msb = duo.msb();
let div_msb = div.msb();
duo.neg_(duo_msb);
div.neg_(div_msb);
Bits::udivide(quo, rem, duo, div).unwrap();
duo.neg_(duo_msb);
rem.neg_(duo_msb);
div.neg_(div_msb);
quo.neg_(duo_msb != div_msb);
Some(())
}
}