use super::add::{SMALL, read_small};
use super::div::{
EUCLID, Medium, Normal, Powers, Prepared, REM_1_PREPARED, Short, TRUNCATED, WIDER, Want,
by_medium, by_zero, compute_by, mu_prepared, normalize, prepare, rem_1, remainder_of_1,
wide_division, wide_number, wider_division, working_memory,
};
use super::mul::{Operand, Product, STACK_LIMBS, WIDE, Wide, on_heap, on_stack, put_wide};
use super::sub::Negated;
use super::{ByteOrder, Number};
use core::mem::MaybeUninit;
use core::ops::{Div, DivAssign, Rem, RemAssign};
use core::ptr;
use std::sync::OnceLock;
#[derive(Clone)]
pub struct Divisor {
limbs: Vec<Pair>,
n: usize,
shift: u32,
v: u64,
negative: bool,
short: Option<Short>,
medium: Option<Medium>,
powers: Option<Powers>,
prepared: OnceLock<Prepared>,
}
#[derive(Clone, Copy)]
#[repr(align(16))]
struct Pair(#[expect(dead_code, reason = "read through pointers to its limbs")] [u64; 2]);
impl Divisor {
#[track_caller]
pub fn new(d: &Number) -> Divisor {
let y = Operand::of(d);
if y.significant == 0 {
by_zero::<false>();
}
let n = y.significant.div_ceil(8);
let mut limbs = vec![Pair([0; 2]); n.div_ceil(2)];
let normal = unsafe { normalize(y, limbs.as_mut_ptr().cast()) };
let short = (y.significant <= SMALL).then(|| {
let magnitude = unsafe {
let start = if y.big_endian {
y.len - y.significant
} else {
0
};
read_small(&d.value[start..start + y.significant], d.byte_order)
};
Short::of(magnitude, d.negative)
});
let medium = (y.significant > SMALL && y.significant <= WIDE).then(|| {
unsafe { Medium::normalized(normal.d, n, normal.shift, normal.v, d.negative) }
});
let powers = short
.map(|s| s.y)
.filter(|&y| (2..=u128::from(u64::MAX)).contains(&y))
.map(|y| Powers::of(y as u64));
Divisor {
limbs,
n,
shift: normal.shift,
v: normal.v,
negative: d.negative,
short,
medium,
powers,
prepared: OnceLock::new(),
}
}
pub fn is_negative(&self) -> bool {
self.negative
}
pub fn div_rem(&self, a: &Number) -> (Number, Number) {
let order = a.byte_order;
if let Some((q, r)) = self.in_registers::<TRUNCATED>(a) {
return (wide_number(order, &q), wide_number(order, &r));
}
unsafe {
self.divide::<TRUNCATED, _>(Operand::of(a), a.negative, Want::Both, |q, r| {
(new_number(q, order), new_number(r, order))
})
}
}
pub fn div_euclid(&self, a: &Number) -> Number {
self.one_new::<EUCLID, false>(a)
}
pub fn rem_euclid(&self, a: &Number) -> Number {
self.one_new::<EUCLID, true>(a)
}
pub fn div_floor(&self, a: &Number) -> Number {
if self.negative {
-self.one_new::<EUCLID, false>(&Negated::new(a))
} else {
self.one_new::<EUCLID, false>(a)
}
}
pub fn rem_floor(&self, a: &Number) -> Number {
if self.negative {
-self.one_new::<EUCLID, true>(&Negated::new(a))
} else {
self.one_new::<EUCLID, true>(a)
}
}
#[inline(always)]
fn normal(&self) -> Normal {
Normal {
d: self.limbs.as_ptr().cast(),
n: self.n,
shift: self.shift,
v: self.v,
pre: ptr::null(),
}
}
#[inline(always)]
fn in_registers<const EUCLIDEAN: bool>(&self, a: &Number) -> Option<(Wide, Wide)> {
let len = a.value.len();
unsafe {
if let Some(y) = self.short {
if len <= SMALL {
Some(wide_division::<EUCLIDEAN, 2>(a, y))
} else if len <= WIDE {
Some(wide_division::<EUCLIDEAN, 4>(a, y))
} else if len <= WIDER {
Some(wider_division::<EUCLIDEAN>(a, y))
} else {
None
}
} else if let Some(y) = self.medium
&& len <= WIDER
{
Some(by_medium::<EUCLIDEAN>(a, y))
} else {
None
}
}
}
#[inline(never)]
fn one_new<const EUCLIDEAN: bool, const REM: bool>(&self, a: &Number) -> Number {
let order = a.byte_order;
if let Some((q, r)) = self.in_registers::<EUCLIDEAN>(a) {
return wide_number(order, if REM { &r } else { &q });
}
unsafe {
self.divide::<EUCLIDEAN, _>(
Operand::of(a),
a.negative,
Want::of(EUCLIDEAN, REM),
|q, r| new_number(if REM { r } else { q }, order),
)
}
}
#[inline(never)]
fn assign<const REM: bool>(&self, a: &mut Number) {
let order = a.byte_order;
if let Some((q, r)) = self.in_registers::<TRUNCATED>(a) {
let w = if REM { &r } else { &q };
put_wide(&mut a.value, order, w);
a.negative = w.negative;
return;
}
let (x, negative_x) = (Operand::of(a), a.negative);
unsafe {
self.divide::<TRUNCATED, _>(x, negative_x, Want::of(TRUNCATED, REM), |q, r| {
let p = if REM { r } else { q };
p.put_in(&mut a.value, order);
a.negative = p.negative;
});
}
}
#[inline(always)]
unsafe fn divide<const EUCLIDEAN: bool, R>(
&self,
x: Operand,
negative_x: bool,
want: Want,
place: impl FnOnce(&Product, &Product) -> R,
) -> R {
if want == Want::Remainder
&& x.significant >= REM_1_PREPARED
&& let Some(p) = &self.powers
{
let r = unsafe { rem_1(x, p) };
return remainder_of_1::<EUCLIDEAN, R>(r, p.d, negative_x && x.significant != 0, place);
}
let nx = x.significant.div_ceil(8).max(self.n);
let need = working_memory(nx, self.n, want);
let (mut y, negative_y) = (self.normal(), self.negative);
if self.n >= 3 && mu_prepared(nx + 1, self.n) {
y.pre = self.prepared.get_or_init(|| unsafe { prepare(y.d, y.n) });
}
let compute = |s: *mut MaybeUninit<u64>| {
unsafe {
compute_by::<EUCLIDEAN, R>(s.cast(), x, y, negative_x, negative_y, want, place)
}
};
if need <= STACK_LIMBS {
on_stack(compute)
} else {
on_heap(need, compute)
}
}
}
impl Div<&Divisor> for &Number {
type Output = Number;
fn div(self, d: &Divisor) -> Number {
d.one_new::<TRUNCATED, false>(self)
}
}
impl Div<&Divisor> for Number {
type Output = Number;
fn div(mut self, d: &Divisor) -> Number {
self /= d;
self
}
}
impl DivAssign<&Divisor> for Number {
fn div_assign(&mut self, d: &Divisor) {
d.assign::<false>(self);
}
}
impl Rem<&Divisor> for &Number {
type Output = Number;
fn rem(self, d: &Divisor) -> Number {
d.one_new::<TRUNCATED, true>(self)
}
}
impl Rem<&Divisor> for Number {
type Output = Number;
fn rem(mut self, d: &Divisor) -> Number {
self %= d;
self
}
}
impl RemAssign<&Divisor> for Number {
fn rem_assign(&mut self, d: &Divisor) {
d.assign::<true>(self);
}
}
#[inline(always)]
unsafe fn new_number(p: &Product, order: ByteOrder) -> Number {
let mut v = Vec::with_capacity(p.len);
unsafe {
p.write(v.as_mut_ptr(), order);
v.set_len(p.len);
}
Number {
value: v,
negative: p.negative,
byte_order: order,
}
}