use core::marker::PhantomData;
use crate::{Exponent, Integer};
#[derive(Clone, Copy)]
#[repr(C)] pub struct Digits<D, const N: usize, const M: usize = 1, const E: usize = 0>(
[[u8; N]; M],
[u8; E],
PhantomData<D>,
);
impl<D, const N: usize> Digits<D, N, 1, 0> {
#[inline(always)]
pub const fn from_integer<const S: bool, const B: usize, const OM: u8>(
int: Integer<S, N, B, OM>,
) -> Self {
debug_assert!(
Self::DIGIT_BYTES == 1
|| Self::DIGIT_BYTES == 2
|| Self::DIGIT_BYTES == 4
|| Self::DIGIT_BYTES == 8
|| Self::DIGIT_BYTES == 16
);
const {
assert!(core::mem::size_of::<Self>() == core::mem::size_of::<Integer<S, N, B, OM>>());
assert!(core::mem::align_of::<Self>() == core::mem::align_of::<Integer<S, N, B, OM>>()); }
unsafe { core::mem::transmute_copy(&int) }
}
#[inline(always)]
pub const fn from_integer_ref<'a, const S: bool, const B: usize, const OM: u8>(
int: &'a Integer<S, N, B, OM>,
) -> &'a Self {
debug_assert!(
Self::DIGIT_BYTES == 1
|| Self::DIGIT_BYTES == 2
|| Self::DIGIT_BYTES == 4
|| Self::DIGIT_BYTES == 8
|| Self::DIGIT_BYTES == 16
);
unsafe { &*(int as *const Integer<S, N, B, OM> as *const Self) }
}
#[inline(always)]
pub const fn to_integer<const S: bool, const B: usize, const OM: u8>(
self,
) -> Integer<S, N, B, OM> {
const {
assert!(core::mem::size_of::<Self>() == core::mem::size_of::<Integer<S, N, B, OM>>());
assert!(core::mem::align_of::<Self>() == core::mem::align_of::<Integer<S, N, B, OM>>()); }
unsafe { core::mem::transmute_copy(&self) }
}
#[inline(always)]
pub const fn grow<const M: usize, const E: usize>(self) -> Digits<D, N, M, E> {
let mut head = [[0u8; N]; M];
head[0] = self.0[0];
let tail = [0u8; E];
Digits(head, tail, PhantomData)
}
}
impl<D, const N: usize, const M: usize, const E: usize> Digits<D, N, M, E> {
#[inline(always)]
const fn as_ptr(&self) -> *const u8 {
self.0.as_ptr() as _
}
#[inline(always)]
const fn as_mut_ptr(&mut self) -> *mut u8 {
self.0.as_mut_ptr() as _
}
#[inline(always)]
const fn force_digit<C>(self) -> Digits<C, N, M, E> {
Digits(self.0, self.1, PhantomData)
}
const ALL_ZEROS: Self = Self([[0; N]; M], [0; E], PhantomData);
const ALL_ONES: Self = Self([[u8::MAX; N]; M], [u8::MAX; E], PhantomData);
const BYTE_LEN: usize = M * N + E;
const BITS: u32 = Self::BYTE_LEN as u32 * 8;
const DIGIT_BYTES: usize = core::mem::size_of::<D>();
const DIGIT_LEN: usize = Self::BYTE_LEN.div_ceil(Self::DIGIT_BYTES);
const LAST_DIGIT_BYTES: usize = {
if Self::BYTE_LEN % Self::DIGIT_BYTES == 0 {
Self::DIGIT_BYTES
} else {
Self::BYTE_LEN % Self::DIGIT_BYTES
}
};
const LAST_DIGIT_BITS: u32 = Self::LAST_DIGIT_BYTES as u32 * 8;
const LAST_DIGIT_PAD_BYTES: usize = Self::DIGIT_BYTES - Self::LAST_DIGIT_BYTES;
const LAST_DIGIT_OFFSET: usize = Self::BYTE_LEN - Self::LAST_DIGIT_BYTES;
}
macro_rules! digits_impl {
{ $name: ident; type $digit_name: ident = $($digit_type: ident), *; $impl_block: item } => {
mod $name {
$(
mod $digit_type {
use super::super::*;
type $digit_name = $digit_type;
$impl_block
}
)*
}
}
}
digits_impl! {
indices;
type Digit = u8, u16, u32, u64, u128;
#[allow(dead_code)]
impl<const N: usize, const M: usize, const E: usize> Digits<Digit, N, M, E> {
#[inline]
pub const fn get(&self, index: usize) -> Digit {
debug_assert!(index < Self::DIGIT_LEN);
if Self::DIGIT_BYTES == 1 {
return unsafe { *(self.as_ptr().add(index) as *const _) };
}
if index == Self::DIGIT_LEN - 1 {
return self.last();
}
let mut bytes = [0; { core::mem::size_of::<Digit>() }];
unsafe {
self.as_ptr()
.add(index * Self::DIGIT_BYTES)
.copy_to_nonoverlapping(bytes.as_mut_ptr(), Self::DIGIT_BYTES);
}
Digit::from_le_bytes(bytes)
}
#[inline]
pub const fn last_padded<const ONES: bool>(&self) -> Digit {
let mut bytes = if ONES {
[u8::MAX; { core::mem::size_of::<Digit>() }]
} else {
[0; { core::mem::size_of::<Digit>() }]
};
unsafe {
self.as_ptr()
.add(Self::LAST_DIGIT_OFFSET)
.copy_to_nonoverlapping(bytes.as_mut_ptr(), Self::LAST_DIGIT_BYTES);
}
Digit::from_le_bytes(bytes)
}
#[inline]
pub const fn last(&self) -> Digit {
self.last_padded::<false>()
}
#[inline]
pub const fn set(&mut self, index: usize, value: Digit) {
debug_assert!(index < Self::DIGIT_LEN);
let bytes = value.to_le_bytes();
if Self::DIGIT_BYTES == 1 {
unsafe { *(self.as_mut_ptr().add(index) as *mut _) = value };
return;
}
if index == Self::DIGIT_LEN - 1 {
return self.set_last(value);
}
unsafe {
self.as_mut_ptr()
.add(index * Self::DIGIT_BYTES)
.copy_from_nonoverlapping(bytes.as_ptr(), Self::DIGIT_BYTES);
}
}
#[inline]
pub const fn set_last(&mut self, value: Digit) {
let bytes = value.to_le_bytes();
unsafe {
self.as_mut_ptr()
.add(Self::LAST_DIGIT_OFFSET)
.copy_from_nonoverlapping(bytes.as_ptr(), Self::LAST_DIGIT_BYTES);
}
}
#[inline]
pub const fn set_be(&mut self, index: usize, value: Digit) {
debug_assert!(index < Self::DIGIT_LEN);
if Self::DIGIT_BYTES == 1 {
unsafe { *(self.as_mut_ptr().add(Self::BYTE_LEN - 1 - index) as *mut _) = value };
return;
}
if index == Self::DIGIT_LEN - 1 {
return self.set_last_be(value);
}
let bytes = value.to_le_bytes();
unsafe {
self.as_mut_ptr()
.add(Self::BYTE_LEN - (index + 1) * Self::DIGIT_BYTES)
.copy_from_nonoverlapping(bytes.as_ptr(), Self::DIGIT_BYTES);
}
}
#[inline]
pub const fn set_last_be(&mut self, value: Digit) {
let bytes = value.to_le_bytes();
unsafe {
self.as_mut_ptr().copy_from_nonoverlapping(
bytes.as_ptr().add(Self::DIGIT_BYTES - Self::LAST_DIGIT_BYTES),
Self::LAST_DIGIT_BYTES,
);
}
}
}
}
digits_impl! {
methods;
type Digit = u8, u16, u32, u64, u128;
#[allow(dead_code)] impl<const N: usize, const M: usize, const E: usize> Digits<Digit, N, M, E> {
#[inline]
pub const fn count_ones(self) -> Exponent {
let mut ones = 0;
let mut i = 0;
while i < Self::DIGIT_LEN {
let digit = self.get(i);
ones += digit.count_ones();
i += 1;
}
ones
}
#[inline]
pub const fn trailing_zeros(self) -> Exponent {
let mut zeros = 0;
let mut i = 0;
while i < Self::DIGIT_LEN {
let digit = self.get(i);
let tz = digit.trailing_zeros();
zeros += tz;
if tz != Digit::BITS {
return zeros;
}
i += 1;
}
zeros
}
#[inline]
pub const fn leading_ones(self) -> Exponent {
let mut ones = 0;
let mut i = Self::DIGIT_LEN;
while i > 0 {
i -= 1;
let digit = self.get(i);
ones += digit.leading_ones();
if digit != Digit::MAX {
break;
}
}
ones
}
#[inline]
pub const fn leading_zeros(self) -> Exponent {
let mut zeros = 0;
let mut i = Self::DIGIT_LEN;
while i > 0 {
i -= 1;
let digit = self.get(i);
let lz = digit.leading_zeros();
zeros += lz;
if lz != Digit::BITS {
return zeros - (Self::LAST_DIGIT_PAD_BYTES as u32 * 8);
}
}
zeros - (Self::LAST_DIGIT_PAD_BYTES as u32 * 8)
}
#[inline]
pub const fn leading_zeros2(&self) -> Exponent {
let mut zeros = 0;
let mut i = Self::DIGIT_LEN;
while i > 0 {
i -= 1;
let digit = self.get(i);
let lz = digit.leading_zeros();
zeros += lz;
if lz != Digit::BITS {
return zeros - (Self::LAST_DIGIT_PAD_BYTES as u32 * 8);
}
}
zeros - (Self::LAST_DIGIT_PAD_BYTES as u32 * 8)
}
#[inline]
pub const fn bit_width(self) -> Exponent {
Self::BITS - self.leading_zeros()
}
#[inline]
pub const fn swap_bytes(self) -> Self {
let mut out = Self::ALL_ZEROS;
let mut i = 0;
while i < Self::DIGIT_LEN {
let d = self.get(i);
out.set_be(i, d.swap_bytes());
i += 1;
}
out
}
#[inline]
pub const fn reverse_bits(self) -> Self {
let mut out = Self::ALL_ZEROS;
let mut i = 0;
while i < Self::DIGIT_LEN {
let d = self.get(i);
out.set_be(i, d.reverse_bits());
i += 1;
}
out
}
#[inline]
pub const fn eq(&self, other: &Self) -> bool {
let mut i = 0;
while i < Self::DIGIT_LEN {
if self.get(i) != other.get(i) {
return false;
}
i += 1;
}
true
}
#[inline]
pub const fn cmp(&self, other: &Self) -> core::cmp::Ordering {
let mut i = Self::DIGIT_LEN;
while i > 0 {
i -= 1;
let a = self.get(i);
let b = other.get(i);
if a > b {
return core::cmp::Ordering::Greater;
} else if a < b {
return core::cmp::Ordering::Less;
}
}
core::cmp::Ordering::Equal
}
#[inline]
pub const fn bitand(self, rhs: Self) -> Self {
let mut out = Self::ALL_ZEROS;
let mut i = 0;
while i < Self::DIGIT_LEN {
let d = self.get(i) & rhs.get(i);
out.set(i, d);
i += 1;
}
out
}
#[inline]
pub const fn bitor(self, rhs: Self) -> Self {
let mut out = Self::ALL_ZEROS;
let mut i = 0;
while i < Self::DIGIT_LEN {
let d = self.get(i) | rhs.get(i);
out.set(i, d);
i += 1;
}
out
}
#[inline]
pub const fn bitxor(self, rhs: Self) -> Self {
let mut out = Self::ALL_ZEROS;
let mut i = 0;
while i < Self::DIGIT_LEN {
let d = self.get(i) ^ rhs.get(i);
out.set(i, d);
i += 1;
}
out
}
#[inline]
pub const fn not(self) -> Self {
let mut out = Self::ALL_ZEROS;
let mut i = 0;
while i < Self::DIGIT_LEN {
let d = !self.get(i);
out.set(i, d);
i += 1;
}
out
}
#[inline]
pub const fn is_power_of_two(self) -> bool {
let mut i = 0;
let mut ones = 0;
while i < Self::DIGIT_LEN {
ones += self.get(i).count_ones();
if ones > 1 {
return false;
}
i += 1;
}
ones == 1
}
#[inline]
pub const fn digit_carrying_add(a: Digit, b: Digit, carry: bool) -> (Digit, bool) {
let (s1, o1) = a.overflowing_add(b);
let (s2, o2) = s1.overflowing_add(carry as Digit); (s2, o1 || o2)
}
#[inline]
pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) {
let mut out = Self::ALL_ZEROS;
let mut carry = false;
let mut i = 0;
let mut result = (0, false);
while i < Self::DIGIT_LEN {
result = Self::digit_carrying_add(self.get(i), rhs.get(i), carry);
out.set(i, result.0);
carry = result.1;
i += 1;
}
if Self::LAST_DIGIT_BITS != Digit::BITS {
carry = (Digit::BITS - result.0.leading_zeros()) > Self::LAST_DIGIT_BITS;
if carry {
debug_assert!(result.0.leading_zeros() == Digit::BITS - Self::LAST_DIGIT_BITS - 1);
}
}
(out, carry)
}
#[inline]
pub const fn digit_borrowing_sub(a: Digit, b: Digit, borrow: bool) -> (Digit, bool) {
let (s1, o1) = a.overflowing_sub(b);
let (s2, o2) = s1.overflowing_sub(borrow as Digit); (s2, o1 || o2)
}
#[inline]
pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) {
let mut out = Self::ALL_ZEROS;
let mut borrow = false;
let mut i = 0;
while i < Self::DIGIT_LEN {
let result = Self::digit_borrowing_sub(self.get(i), rhs.get(i), borrow);
out.set(i, result.0);
borrow = result.1;
i += 1;
}
(out, borrow)
}
#[inline]
pub const fn long_mul<const WIDEN: bool>(self, rhs: Self) -> (Self, bool) {
let mut overflow = false;
let mut out = Self::ALL_ZEROS;
let mut prod: Digit = 0;
let mut i = 0;
loop {
if (WIDEN && i >= Self::DIGIT_LEN.div_ceil(2)) || (!WIDEN && i >= Self::DIGIT_LEN) {
break;
}
let mut carry = 0;
let mut j = 0;
loop {
if (WIDEN && j >= Self::DIGIT_LEN.div_ceil(2)) || (!WIDEN && i + j >= Self::DIGIT_LEN) {
break;
}
let index = i + j;
(prod, carry) = Self::digit_carrying_mul_add(
self.get(i),
rhs.get(j),
carry,
out.get(index),
);
out.set(index, prod);
j += 1;
}
if WIDEN {
if Self::DIGIT_LEN.div_ceil(2) * 2 > Self::DIGIT_LEN && i == Self::DIGIT_LEN.div_ceil(2) - 1 {
debug_assert!(carry == 0);
} else {
out.set(i + Self::DIGIT_LEN.div_ceil(2), carry);
}
}
if Self::LAST_DIGIT_BITS != Digit::BITS && Digit::BITS - Self::LAST_DIGIT_BITS > prod.leading_zeros() {
overflow = true;
} else if carry != 0 {
overflow = true;
} else if self.get(i) != 0 {
while j < Self::DIGIT_LEN {
if rhs.get(j) != 0 {
overflow = true;
break;
}
j += 1;
}
}
i += 1;
}
(out, overflow)
}
#[inline]
pub(crate) const fn mul_digit(self, rhs: Digit) -> (Self, bool, ) {
let mut out = Self::ALL_ZEROS;
let (mut prod, mut carry) = (0, 0);
let mut i = 0;
while i < Self::DIGIT_LEN {
let d = self.get(i);
(prod, carry) = Self::digit_carrying_mul_add(d, rhs, carry, 0);
out.set(i, prod);
i += 1;
}
let overflow = carry != 0
|| (Self::LAST_DIGIT_BITS != Digit::BITS
&& Digit::BITS - prod.leading_zeros() > Self::LAST_DIGIT_BITS);
(out, overflow)
}
#[inline]
pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) {
self.long_mul::<false>(rhs)
}
#[inline]
pub const unsafe fn unchecked_shl(self, rhs: Exponent) -> Self {
let byte_shift = (rhs / 8) as usize;
let bit_shift = rhs % 8;
let mut out = Self::ALL_ZEROS;
unsafe {
out
.as_mut_ptr()
.add(byte_shift)
.copy_from_nonoverlapping(self.as_ptr(), Self::BYTE_LEN - byte_shift);
}
if bit_shift != 0 {
let carry_shift = Digit::BITS - bit_shift;
let mut carry = 0;
let mut i = (rhs / Digit::BITS) as usize;
while i < Self::DIGIT_LEN {
let d = out.get(i);
out.set(i, (d << bit_shift) | carry);
carry = d >> carry_shift;
i += 1;
}
}
out
}
#[inline]
pub(crate) const unsafe fn unchecked_shr(self, rhs: Exponent, negative_sign_extend: bool) -> Self {
let mut out = if negative_sign_extend {
Self::ALL_ONES
} else {
Self::ALL_ZEROS
};
let byte_shift = (rhs / 8) as usize;
let bit_shift = rhs % 8;
unsafe {
out
.as_mut_ptr()
.copy_from_nonoverlapping(self.as_ptr().add(byte_shift), Self::BYTE_LEN - byte_shift);
}
if bit_shift != 0 {
let carry_shift = Digit::BITS - bit_shift;
let mut i = (Self::BITS - rhs).div_ceil(Digit::BITS) as usize;
let mut carry = if negative_sign_extend {
let shift_back = if Self::LAST_DIGIT_BITS == Digit::BITS || i != Self::DIGIT_LEN {
carry_shift
} else {
Self::LAST_DIGIT_BITS - bit_shift
};
Digit::MAX << shift_back } else {
0
};
while i > 0 {
i -= 1;
let current_digit = out.get(i);
out.set(i, (current_digit >> bit_shift) | carry);
carry = current_digit << carry_shift;
}
}
out
}
#[inline]
pub const unsafe fn unchecked_rotate_left(self, rhs: Exponent) -> Self {
let digit_shift = (rhs / 8) as usize;
let bit_shift = rhs % 8;
let mut out = self;
unsafe {
out.as_mut_ptr().add(digit_shift).copy_from_nonoverlapping(self.as_ptr(), Self::BYTE_LEN - digit_shift);
out.as_mut_ptr().copy_from_nonoverlapping(self.as_ptr().add(Self::BYTE_LEN - digit_shift), digit_shift);
}
if bit_shift != 0 {
let carry_shift = Digit::BITS - bit_shift;
let mut carry =
out.last() >> (Self::LAST_DIGIT_BITS - bit_shift);
let mut i = 0;
while i < Self::DIGIT_LEN {
let current_digit = out.get(i);
out
.set(i, (current_digit << bit_shift) | carry);
carry = current_digit >> carry_shift;
i += 1;
}
}
out
}
}
}
#[cfg(any(test, feature = "quickcheck"))]
digits_impl! {
quickcheck_arbitrary;
type Digit = u8, u16, u32, u64, u128;
impl<const N: usize, const M: usize, const E: usize> quickcheck::Arbitrary for Digits<Digit, N, M, E> {
#[inline]
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
let mut out = Self::ALL_ZEROS;
for i in 0..Self::DIGIT_LEN {
out.set(i, <Digit as quickcheck::Arbitrary>::arbitrary(g));
}
out
}
}
}
trait DoubleDigit: Sized {
type Double;
}
impl DoubleDigit for u8 {
type Double = u16;
}
impl DoubleDigit for u16 {
type Double = u32;
}
impl DoubleDigit for u32 {
type Double = u64;
}
impl DoubleDigit for u64 {
type Double = u128;
}
impl<const N: usize, const M: usize, const E: usize> Digits<u128, N, M, E> {
#[inline]
pub const fn digit_carrying_mul_add(
a: u128,
b: u128,
carry: u128,
current: u128,
) -> (u128, u128) {
let (a_lo, a_hi) = (a as u64, (a >> 64) as u64);
let (b_lo, b_hi) = (b as u64, (b >> 64) as u64);
let (c_lo, c_hi) = (carry as u64, (carry >> 64) as u64);
let (d_lo, d_hi) = (current as u64, (current >> 64) as u64);
let x = (a_lo as u128) * (b_lo as u128) + (c_lo as u128) + (d_lo as u128);
let y = (a_lo as u128) * (b_hi as u128) + (c_hi as u128) + (d_hi as u128);
let (y, carry_y) = y.overflowing_add((a_hi as u128) * (b_lo as u128));
let (x, carry_x) = x.overflowing_add(y << 64);
let carry2 = if carry_y { 1 << 64 } else { 0 };
let carry3 = if carry_x { 1 } else { 0 };
let z = (a_hi as u128) * (b_hi as u128) + carry2 + carry3 + (y >> 64);
(x, z)
}
}
digits_impl! {
knuth_division;
type Digit = u8, u16, u32, u64;
#[allow(dead_code)]
impl<const N: usize, const M: usize, const E: usize> Digits<Digit, N, M, E> {
#[inline]
pub const fn digit_carrying_mul_add(a: Digit, b: Digit, c: Digit, carry: Digit) -> (Digit, Digit) {
type Double = <Digit as DoubleDigit>::Double;
let prod = (a as Double) * (b as Double) + (c as Double) + (carry as Double);
(prod as Digit, (prod >> Digit::BITS) as Digit)
}
#[inline]
const fn digit_div_rem_wide(low: Digit, high: Digit, rhs: Digit) -> (Digit, Digit) {
type Double = <Digit as DoubleDigit>::Double;
debug_assert!(high < rhs);
let a = ((high as Double) << Digit::BITS) | (low as Double);
(
(a / rhs as Double) as Digit,
(a % rhs as Double) as Digit,
)
}
#[inline]
pub(crate) const fn div_rem_digit(self, rhs: Digit) -> (Self, Digit) {
let mut out = Self::ALL_ZEROS;
let mut rem: Digit = 0;
let mut i = Self::DIGIT_LEN;
while i > 0 {
i -= 1;
let d = self.get(i);
let (q, r) = Self::digit_div_rem_wide(d, rem, rhs);
rem = r;
out.set(i, q);
}
(out, rem)
}
#[inline(always)]
const fn digit_widening_mul(a: Digit, b: Digit) -> (Digit, Digit) {
Self::digit_carrying_mul_add(a, b, 0, 0)
}
const fn div_rem_knuth_wide(mut self, rhs: Self, n: usize) -> (Self, Self) {
debug_assert!(n >= 2);
let m = self.bit_width().div_ceil(Digit::BITS) as usize - n;
let e = rhs.get(n - 1).leading_zeros();
let mut q = Self::ALL_ZEROS;
let v_dash = (rhs.get(n - 1) << e)
| (rhs.get(n - 2).unbounded_shr(Digit::BITS - e));
let v_dash_dash = {
let mut out = rhs.get(n - 2) << e;
if n >= 3 {
out |= rhs.get(n - 3).unbounded_shr(Digit::BITS - e);
}
out
};
let mut j = m + 1; while j > 0 {
j -= 1;
let u_dash = if j + n == Self::DIGIT_LEN {
self.get(j + n - 1).unbounded_shr(Digit::BITS - e)
} else {
(self.get(j + n) << e) | (self.get(j + n - 1).unbounded_shr(Digit::BITS - e))
};
let u_dash_dash = (self.get(j + n - 1) << e)
| (self.get(j + n - 2)
.unbounded_shr(Digit::BITS - e));
let u_dash_dash_dash = if j + n >= 3 {
(self.get(j + n - 2) << e) | (self.get(j + n - 3).unbounded_shr(Digit::BITS - e))
} else {
self.get(j + n - 2) << e
};
let mut q_hat = if u_dash < v_dash {
let (mut q, r) = Self::digit_div_rem_wide(u_dash_dash, u_dash, v_dash);
#[inline(always)]
const fn digit_tuple_gt(a: (Digit, Digit), b: (Digit, Digit)) -> bool {
a.1 > b.1 || a.1 == b.1 && a.0 > b.0
}
if digit_tuple_gt(
Self::digit_widening_mul(q, v_dash_dash),
(u_dash_dash_dash, r),
) {
q -= 1;
if let Some(r) = r.checked_add(v_dash) {
if digit_tuple_gt(
Self::digit_widening_mul(q, v_dash_dash),
(u_dash_dash_dash, r),
) {
q -= 1;
}
}
}
q
} else {
Digit::MAX
};
let borrow = {
let (m, overflow) = rhs.force_digit::<u128>().mul_digit(q_hat as u128);
let m = m.force_digit::<Digit>();
let borrow = self.sub_partial(m, j, n);
if overflow {
debug_assert!(n == Self::BITS.div_ceil(Digit::BITS) as usize);
}
overflow || borrow
};
if borrow {
q_hat -= 1;
self.add_partial(rhs, j, n);
}
q.set(j, q_hat);
}
(q, self)
}
#[inline]
const fn sub_partial(&mut self, rhs: Self, start: usize, range: usize) -> bool {
let mut borrow = false;
let mut i = 0;
while i <= range {
if i + start == Self::DIGIT_LEN {
if i < Self::DIGIT_LEN && rhs.get(i) != 0 {
borrow = true;
}
} else {
let (sub, overflow) = Self::digit_borrowing_sub(
self.get(i + start),
rhs.get(i),
borrow,
);
self.set(i + start, sub);
borrow = overflow;
}
i += 1;
}
borrow
}
#[inline]
const fn add_partial(&mut self, rhs: Self, start: usize, range: usize) {
let mut carry = false;
let mut i = 0;
while i < range {
let (sum, overflow) = Self::digit_carrying_add(
self.get(i + start),
rhs.get(i),
carry,
);
self.set(i + start, sum);
carry = overflow;
i += 1;
}
if carry {
if range + start != Self::DIGIT_LEN {
self.set(
range + start,
self.get(range + start).wrapping_add(1),
);
}
}
}
#[inline]
pub(crate) const fn div_rem_unchecked(self, rhs: Self) -> (Self, Self) {
debug_assert!(!rhs.eq(&Self::ALL_ZEROS));
debug_assert!(self.cmp(&rhs).is_gt());
let bit_width = rhs.bit_width();
if bit_width <= Digit::BITS {
let d = rhs.get(0);
let (div, rem) = self.div_rem_digit(d);
let mut out = Self::ALL_ZEROS;
out.set(0, rem);
(div, out)
} else {
self.div_rem_knuth_wide(rhs, bit_width.div_ceil(Digit::BITS) as usize)
}
}
}
}