use std::borrow::Cow; use std::cmp::Ordering; use std::fmt::{Debug, Display, Write}; use std::intrinsics::{const_deallocate, const_eval_select}; use std::marker::Destruct; use std::mem::{ManuallyDrop as MD, forget, replace, transmute}; use std::ops::{ Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Neg, Rem, Shl, Shr, Sub, SubAssign, }; #[cfg(test)] mod test; use crate::xp::{self, XP}; #[repr(C)] /// Arbitratry precision integer, usable in const pub struct AP { // -1 | +1 sign: i8, ndigits: u32, digits: MD, } impl const Eq for AP {} impl const PartialEq for AP { fn eq(&self, other: &Self) -> bool { self.sign == other.sign && self.ndigits == other.ndigits && self.dgr()[..self.ndigits as usize] == other.dgr()[..other.ndigits as usize] } } impl const Drop for Storage { fn drop(&mut self) { const fn drop_c(x: &mut MD>) { unsafe { const_deallocate(x.as_mut_ptr(), x.capacity(), 0) }; } fn drop_r(x: &mut MD>) { unsafe { MD::drop(x) }; } match self { Self::V(x) => { const_eval_select((x,), drop_c, drop_r); } _ => {} } } } impl const DerefMut for Storage { fn deref_mut(&mut self) -> &mut Self::Target { match self { Self::V(x) => x.as_mut_slice(), Self::Leaked(items) => { let mut v = Vec::new(); let mut i = 0; while i < items.len() { v.push(items[i]); } *self = Storage::V(MD::new(v)); &mut *self } } } } impl const Deref for Storage { type Target = [u8]; fn deref(&self) -> &Self::Target { match self { Self::V(x) => x.as_slice(), Self::Leaked(items) => *items, } } } impl const Clone for AP { fn clone(&self) -> Self { Self { sign: self.sign.clone(), ndigits: self.ndigits.clone(), digits: MD::new((&*self.digits).clone()), } } } #[derive(Debug)] pub enum Storage { V(MD>), Leaked(&'static [u8]), } impl const Clone for Storage { fn clone(&self) -> Self { match self { Self::V(x) => { let mut i = 0; let mut v = Vec::with_capacity(x.len()); while i < x.len() { v.push(x.as_slice()[i]); i += 1; } Self::V(MD::new(v)) } Self::Leaked(x) => Self::Leaked(x), } } } impl const Default for AP { fn default() -> Self { Self { sign: 1, ndigits: 1, digits: MD::new(Storage::Leaked(&[0])), } } } impl Debug for AP { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.sign == -1 { f.write_char('-')?; } let mut x = Vec::with_capacity(1024); f.write_str(unsafe { std::str::from_utf8_unchecked(xp::to_str( &mut x, 10, self.ndigits, self.clone().dg(), )) }) } } impl Display for AP { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.sign == -1 { f.write_char('-')?; } let mut x = Vec::with_capacity(1024); f.write_str(unsafe { std::str::from_utf8_unchecked(xp::to_str( &mut x, 10, self.ndigits, self.clone().dg(), )) }) } } impl AP { const fn sz(&self) -> u32 { self.digits.len() as _ } const fn dg(&mut self) -> &mut XP { &mut self.digits } pub const fn new(n: i128) -> Self { let mut x = Self::alloc(8); x.set(n); x } const fn dgr(&self) -> &XP { &self.digits } pub const fn to_int(&self) -> i128 { let u = xp::to_int(self.ndigits, self.dgr()) % (i128::MAX as u128 + 1); if self.sign == -1 { -(u as i128) } else { u as i128 } } pub const fn set(&mut self, n: i128) { if (n == i128::MIN) { xp::from_int(self.sz(), self.dg(), (i128::MAX as u128 + 1)); } else if (n < 0) { xp::from_int(self.sz(), self.dg(), (-n) as _); } else { xp::from_int(self.sz(), self.dg(), (n) as _); self.sign = if n < 0 { -1 } else { 1 }; } self.sign = if n < 0 { -1 } else { 1 }; self.normalize(self.sz()); } const fn normalize(&mut self, n: u32) { self.ndigits = xp::len(n, self.dgr()); } const fn iszero(&self) -> bool { self.ndigits == 1 && self.dgr()[0] == 0 } pub const fn alloc(size: u32) -> Self { assert!(size > 0); let mut v = Vec::with_capacity(size as _); let mut i = 0; while i < size { v.push(0); i += 1; } Self { sign: 1, ndigits: 1, digits: MD::new(Storage::V(MD::new(v))), } } const fn add(z: &mut Self, x: &Self, y: &Self) { let mut n = y.ndigits; if x.ndigits < n { Self::add(z, y, x) } else if (x.ndigits > n) { let carry = xp::add(n, z.dg(), x.dgr(), y.dgr(), false); let sz = z.sz() as usize; z.dg()[sz - 1] = unsafe { xp::sum( x.ndigits - n, &mut z.dg()[n as usize..], &x.dgr()[n as usize..], carry as _, ) }; } else { z.dg()[n as usize] = xp::add(n, z.dg(), x.dgr(), y.dgr(), false) as _; } z.normalize(z.sz()); } const fn sub(z: &mut Self, x: &Self, y: &Self) { let mut n = y.ndigits; // int borrow, n = y->ndigits; let mut borrow = xp::sub(n, z.dg(), x.dgr(), y.dgr(), false) as u8; if (x.ndigits > n) { borrow = xp::diff( x.ndigits - n, &mut z.dg()[n as usize..], &x.dgr()[n as usize..], borrow, ); } assert!(borrow == 0); z.normalize(z.sz()); // assert(borrow == 0); // return normalize(z, z->size); } const fn cmp(x: &Self, y: &Self) -> Ordering { if x.ndigits != y.ndigits { x.ndigits.cmp(&y.ndigits) } else { xp::cmp(x.ndigits, x.dgr(), y.dgr()) } } const fn smsn(x: &Self, y: &Self) -> bool { (x.sign ^ y.sign) == 0 } pub const fn divmod(x: &Self, y: &Self) -> (AP, AP) { assert!(!y.iszero()); let mut q = AP::alloc(x.ndigits); let mut r = AP::alloc(y.ndigits); xp::div( x.ndigits, q.dg(), x.dgr(), y.ndigits, y.dgr(), r.dg(), AP::alloc(x.ndigits + y.ndigits + 2).dg(), ); q.normalize(q.sz()); r.normalize(r.sz()); q.sign = if q.iszero() || AP::smsn(x, y) { 1 } else { -1 }; if !AP::smsn(x, y) && !r.iszero() { let carry = unsafe { xp::sum_p(q.sz(), q.dg().as_mut_ptr(), q.dgr().as_ptr(), 1) }; assert!(carry == 0); q.normalize(q.sz()); assert!(unsafe { !xp::subp( r.sz(), r.dg().as_mut_ptr(), y.dgr().as_ptr(), r.dgr().as_ptr(), false, ) }); r.normalize(r.sz()); }; (q, r) } const fn isone(&self) -> bool { self.ndigits == 1 && self.dgr()[0] == 1 } pub const fn is_even(&self) -> bool { (self.dgr()[0] & 1) == 0 } const fn mulmod(x: &Self, y: &Self, p: &Self) -> AP { let xy = x * y; &xy % p } pub const fn pow(&self, y: &Self) -> AP { assert!(y.sign == 1); if self.iszero() { return AP::new(0); } if y.iszero() { return AP::new(1); } if self.isone() { return AP::new(if y.is_even() { 1 } else { self.sign as _ }); } if y.isone() { return self + 0; } let y2 = y >> 1; let t = AP::pow(self, &y2); let mut z = &t * &t; if !y.is_even() { z = self * &z; } z } pub const fn pow_mod(&self, y: &Self, modulo: &Self) -> Self { assert!(y.sign == 1); assert!(modulo.sign == 1 && !modulo.iszero() && !modulo.isone()); if self.iszero() { return AP::new(0); } if y.iszero() { return AP::new(1); } if self.isone() { return AP::new(if y.is_even() { 1 } else { self.sign as _ }); } if y.isone() { return self + 0; } let y2 = y >> 1; let t = AP::pow_mod(self, &y2, modulo); let mut z = AP::mulmod(&t, &t, modulo); if !y.is_even() { z = AP::mulmod(&(self % modulo), &z, modulo); } z } const fn cmp_(x: &Self, y: &Self) -> Ordering { if x.ndigits != y.ndigits { x.ndigits.cmp(&y.ndigits) } else { xp::cmp(x.ndigits, x.dgr(), y.dgr()) } } /// call before storing. pub const fn globalize(mut self) -> Self { match &mut *self.digits { Storage::V(x) => self.digits = MD::new(Storage::Leaked( unsafe { MD::take(x) }.const_make_global(), )), _ => {} }; self } } impl const Drop for AP { fn drop(&mut self) { unsafe { MD::drop(&mut self.digits) }; } } impl const Neg for AP { type Output = AP; fn neg(mut self) -> Self::Output { self.sign = if self.iszero() { 1 } else { -self.sign }; self } } impl const Mul for &AP { type Output = AP; fn mul(self, rhs: Self) -> Self::Output { let mut z = AP::alloc(self.ndigits + rhs.ndigits); xp::mul(z.dg(), self.ndigits, self.dgr(), rhs.ndigits, rhs.dgr()); z.normalize(z.sz()); z.sign = if z.iszero() || AP::smsn(self, rhs) { 1 } else { -1 }; z } } impl const MulAssign<&AP> for AP { fn mul_assign(&mut self, rhs: &Self) { *self = &*self * rhs; } } impl const Add for &AP { type Output = AP; fn add(self, rhs: Self) -> Self::Output { let mut z; if AP::smsn(&self, &rhs) { z = AP::alloc(self.ndigits.max(rhs.ndigits) + 1); AP::add(&mut z, &self, &rhs); z.sign = if z.iszero() { 1 } else { self.sign }; } else if AP::cmp(self, rhs).is_gt() { z = AP::alloc(self.ndigits); AP::sub(&mut z, self, rhs); z.sign = if z.iszero() { 1 } else { self.sign }; } else { // lesser ? z = AP::alloc(rhs.ndigits); AP::sub(&mut z, rhs, self); z.sign = if z.iszero() { 1 } else { -self.sign }; } z } } impl const Sub for &AP { type Output = AP; fn sub(self, rhs: Self) -> Self::Output { let mut z; if !AP::smsn(self, rhs) { z = AP::alloc(self.ndigits.max(rhs.ndigits) + 1); AP::add(&mut z, self, rhs); z.sign = if z.iszero() { 1 } else { self.sign }; } else if AP::cmp(self, rhs).is_gt() { z = AP::alloc(self.ndigits); AP::sub(&mut z, self, rhs); z.sign = if z.iszero() { 1 } else { self.sign }; } else { z = AP::alloc(rhs.ndigits); AP::sub(&mut z, rhs, self); z.sign = if z.iszero() { 1 } else { -self.sign }; } z } } impl const SubAssign<&AP> for AP { fn sub_assign(&mut self, rhs: &AP) { *self = &*self - rhs; } } impl const AddAssign<&AP> for AP { fn add_assign(&mut self, rhs: &AP) { *self = &*self + rhs; } } impl const Div for &AP { type Output = AP; fn div(self, rhs: Self) -> Self::Output { AP::divmod(self, rhs).0 } } impl const DivAssign<&AP> for AP { fn div_assign(&mut self, rhs: &AP) { *self = &*self / rhs; } } impl const Rem for &AP { type Output = AP; fn rem(self, rhs: Self) -> Self::Output { AP::divmod(self, rhs).1 } } impl const Shl for &AP { type Output = AP; fn shl(self, s: u32) -> Self::Output { let mut z = AP::alloc(self.ndigits + ((s + 7) & !7) / 8); xp::shl(z.sz(), z.dg(), self.ndigits, self.dgr(), s, 0); z.sign = self.sign; z.normalize(z.sz()); z } } impl const Shr for &AP { type Output = AP; /// this is a truncating, not flooring, shr. fn shr(self, s: u32) -> Self::Output { if s >= 8 * self.ndigits { return AP::new(0); } let mut z = AP::alloc(self.ndigits - (s / 8)); let c = xp::shr(z.sz(), z.dg(), self.ndigits, self.dgr(), s, 0); z.sign = if z.iszero() { 1 } else { self.sign }; z.normalize(z.sz()); z } } macro_rules! fni { ($t:ident, $fname:ident => $($for:ident)+) => { impl const $t<&AP> for AP { type Output = AP; fn $fname(self, other: &AP) -> AP { <&AP as $t<&AP>>::$fname(&self, other) } } impl const $t for AP { type Output = AP; fn $fname(self, other: AP) -> AP { <&AP as $t<&AP>>::$fname(&self, &other) } } impl const $t for &AP { type Output = AP; fn $fname(self, other: AP) -> AP { <&AP as $t<&AP>>::$fname(self, &other) } } $(impl const $t<$for> for &AP { type Output = AP; fn $fname(self, other: $for) -> AP { let other = AP::new(other as _); <&AP as $t<&AP>>::$fname(self, &other) } })+ $(impl const $t<$for> for AP { type Output = AP; fn $fname(self, other: $for) -> AP { let other = AP::new(other as _); <&AP as $t<&AP>>::$fname(&self, &other) } })+ }; } fni!(Add, add => u64 u32 u16 u8 i128 i64 i32 i16 i8); fni!(Mul, mul => u64 u32 u16 u8 i128 i64 i32 i16 i8); fni!(Div, div => u64 u32 u16 u8 i128 i64 i32 i16 i8); fni!(Sub, sub => u64 u32 u16 u8 i128 i64 i32 i16 i8); fni!(Rem, rem => u64 u32 u16 u8 i128 i64 i32 i16 i8); impl const PartialOrd for AP { fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } impl const Ord for AP { fn cmp(&self, other: &Self) -> Ordering { if !AP::smsn(self, other) { unsafe { transmute(self.sign) } } else if self.sign == 1 { AP::cmp_(self, other) } else { AP::cmp_(other, self) } } }