use super::compute_limbs::Limbs;
use super::Int;
pub trait BigInt:
Copy
+ PartialEq
+ Eq
+ PartialOrd
+ Ord
+ core::fmt::Debug
+ core::ops::Add<Output = Self>
+ core::ops::Sub<Output = Self>
+ core::ops::Mul<Output = Self>
+ core::ops::Div<Output = Self>
+ core::ops::Rem<Output = Self>
+ core::ops::Neg<Output = Self>
+ core::ops::BitAnd<Output = Self>
+ core::ops::BitOr<Output = Self>
+ core::ops::BitXor<Output = Self>
+ core::ops::Not<Output = Self>
+ core::ops::Shl<u32, Output = Self>
+ core::ops::Shr<u32, Output = Self>
{
type Limbs: Copy;
type Scratch;
const LIMBS: usize;
const BITS: u32;
const ZERO: Self;
const ONE: Self;
const TEN: Self;
const U128_LIMBS: usize;
fn is_zero(self) -> bool;
fn is_one(self) -> bool;
fn wrapping_add(self, rhs: Self) -> Self;
fn wrapping_sub(self, rhs: Self) -> Self;
fn wrapping_mul(self, rhs: Self) -> Self;
#[inline]
fn wrapping_mul_low_u128(self, rhs: Self) -> Self {
self.wrapping_mul(rhs)
}
fn checked_add(self, rhs: Self) -> Option<Self>;
fn checked_sub(self, rhs: Self) -> Option<Self>;
fn checked_mul(self, rhs: Self) -> Option<Self>;
fn pow(self, exp: u32) -> Self;
fn wrapping_pow(self, exp: u32) -> Self;
fn checked_pow(self, exp: u32) -> Option<Self>;
fn sqr(self) -> Self;
#[inline]
fn wrapping_sqr_low_u128(self) -> Self {
self.sqr()
}
fn cube(self) -> Self;
fn bit_length(self) -> u32;
fn leading_zeros(self) -> u32;
fn isqrt(self) -> Self;
fn icbrt(self) -> Self;
fn resize_to<T: BigInt>(self) -> T;
fn div_rem(self, rhs: Self) -> (Self, Self);
fn bit(self, idx: u32) -> bool;
fn from_i128(v: i128) -> Self;
fn to_i128(self) -> i128;
fn mul_u64(self, n: u64) -> Self;
fn to_f64(self) -> f64;
fn from_f64_val(v: f64) -> Self;
fn from_limbs(limbs: Self::Limbs) -> Self;
fn to_limbs(self) -> Self::Limbs;
fn mag_into_u128(self, dst: &mut [u128]) -> bool;
fn from_mag_sign_u128(mag: &[u128], negative: bool) -> Self;
fn from_mag_sign_u64(mag: &[u64], negative: bool) -> Self;
#[inline]
fn sum<I>(iter: I) -> Self
where
I: IntoIterator<Item = Self>,
{
iter.into_iter().fold(Self::ZERO, |acc, x| acc + x)
}
#[inline]
fn product<I>(iter: I) -> Self
where
I: IntoIterator<Item = Self>,
{
iter.into_iter().fold(Self::ONE, |acc, x| acc * x)
}
}
impl<const N: usize> BigInt for Int<N> {
type Limbs = [u64; N];
type Scratch = Limbs<N>;
const LIMBS: usize = N;
const BITS: u32 = (N * 64) as u32;
const ZERO: Self = Int::<N>::ZERO;
const ONE: Self = Int::<N>::ONE;
const TEN: Self = Int::<N>::TEN;
const U128_LIMBS: usize = N.div_ceil(2);
#[inline]
fn is_zero(self) -> bool {
Int::is_zero(&self)
}
#[inline]
fn is_one(self) -> bool {
Int::is_one(&self)
}
#[inline]
fn wrapping_add(self, rhs: Self) -> Self {
Int::wrapping_add(self, rhs)
}
#[inline]
fn wrapping_sub(self, rhs: Self) -> Self {
Int::wrapping_sub(self, rhs)
}
#[inline]
fn wrapping_mul(self, rhs: Self) -> Self {
Int::wrapping_mul(self, rhs)
}
#[inline]
fn wrapping_mul_low_u128(self, rhs: Self) -> Self {
let a = *self.as_limbs();
let b = *rhs.as_limbs();
let mut out = [0u64; N];
crate::int::policy::mul_low::dispatch::<N>(&a, &b, &mut out);
Int::from_limbs(out)
}
#[inline]
fn wrapping_sqr_low_u128(self) -> Self {
let a = *self.as_limbs();
let mut out = [0u64; N];
crate::int::policy::sqr_low::dispatch::<N>(&a, &mut out);
Int::from_limbs(out)
}
#[inline]
fn checked_add(self, rhs: Self) -> Option<Self> {
Int::checked_add(self, rhs)
}
#[inline]
fn checked_sub(self, rhs: Self) -> Option<Self> {
Int::checked_sub(self, rhs)
}
#[inline]
fn checked_mul(self, rhs: Self) -> Option<Self> {
Int::checked_mul(self, rhs)
}
#[inline]
fn pow(self, exp: u32) -> Self {
Int::wrapping_pow(self, exp)
}
#[inline]
fn wrapping_pow(self, exp: u32) -> Self {
Int::wrapping_pow(self, exp)
}
#[inline]
fn checked_pow(self, exp: u32) -> Option<Self> {
Int::checked_pow(self, exp)
}
#[inline]
fn sqr(self) -> Self {
self.wrapping_sqr()
}
#[inline]
fn cube(self) -> Self {
self.wrapping_cube()
}
#[inline]
fn bit_length(self) -> u32 {
Int::bit_length(&self)
}
#[inline]
fn leading_zeros(self) -> u32 {
Int::leading_zeros(&self)
}
#[inline]
fn isqrt(self) -> Self {
Self::from_limbs(*self.unsigned_abs().isqrt().as_limbs())
}
#[inline]
fn icbrt(self) -> Self {
Self::from_limbs(*self.unsigned_abs().icbrt().as_limbs())
}
#[inline]
fn resize_to<T: BigInt>(self) -> T {
let negative = self.is_negative();
let mut u128_mag = [0u128; crate::int::types::compute_limbs::MAX_U128_LIMB];
let u128_len = N.div_ceil(2);
self.mag_into_u128(&mut u128_mag[..u128_len]);
T::from_mag_sign_u128(&u128_mag[..u128_len], negative)
}
#[inline]
fn div_rem(self, rhs: Self) -> (Self, Self) {
Int::div_rem(self, rhs)
}
#[inline]
fn bit(self, idx: u32) -> bool {
Int::bit(self, idx)
}
#[inline]
fn from_i128(v: i128) -> Self {
Int::from_i128(v)
}
#[inline]
fn to_i128(self) -> i128 {
self.as_i128()
}
#[inline]
fn mul_u64(self, n: u64) -> Self {
Int::mul_u64(self, n)
}
#[inline]
fn to_f64(self) -> f64 {
Int::to_f64(self)
}
#[inline]
fn from_f64_val(v: f64) -> Self {
Int::from_f64(v)
}
#[inline]
fn from_limbs(limbs: [u64; N]) -> Self {
Int::from_limbs(limbs)
}
#[inline]
fn to_limbs(self) -> [u64; N] {
*self.as_limbs()
}
#[inline]
fn mag_into_u128(self, dst: &mut [u128]) -> bool {
let mag = *self.unsigned_abs().as_limbs();
let n_full_pairs = N / 2;
let dst_len = dst.len();
let mut i = 0;
let m = n_full_pairs.min(dst_len);
while i < m {
dst[i] = (mag[2 * i] as u128) | ((mag[2 * i + 1] as u128) << 64);
i += 1;
}
if (N & 1) == 1 && i < dst_len && i < <Self as BigInt>::U128_LIMBS {
dst[i] = mag[2 * i] as u128;
i += 1;
}
while i < dst_len {
dst[i] = 0;
i += 1;
}
self.is_negative()
}
#[inline]
fn from_mag_sign_u64(mag: &[u64], negative: bool) -> Self {
Int::from_mag_limbs(mag, negative)
}
#[inline]
fn from_mag_sign_u128(mag: &[u128], negative: bool) -> Self {
let u128_limbs = N.div_ceil(2);
let mut out = [0u64; N];
let m = u128_limbs.min(mag.len());
let n_full_pairs = N / 2;
let copy_pairs = n_full_pairs.min(m);
let mut i = 0;
while i < copy_pairs {
let v = mag[i];
out[2 * i] = v as u64;
out[2 * i + 1] = (v >> 64) as u64;
i += 1;
}
if (N & 1) == 1 && i < m {
out[2 * i] = mag[i] as u64;
}
Self::from_mag_limbs(&out, negative)
}
}