[no description]
Diffstat (limited to 'src/array_ap.rs')
| -rw-r--r-- | src/array_ap.rs | 496 |
1 files changed, 496 insertions, 0 deletions
diff --git a/src/array_ap.rs b/src/array_ap.rs new file mode 100644 index 0000000..e06ccb7 --- /dev/null +++ b/src/array_ap.rs @@ -0,0 +1,496 @@ +#[cfg(test)] +mod test; + +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, +}; +trait Constructible {} +impl<const N: usize> Constructible for [u8; N] {} +use crate::xp::{self, XP}; + +#[derive(Clone)] +pub struct AP<const N: usize = 8> { + /// sign is either 1 or −1. size is the number of digits allocated and pointed + /// to by digits; it can exceed ndigits, which is the number of digits in + /// use. That is, an AP_T represents the number given by the XP_T in dig- + /// its[0..ndigits-1]. AP_Ts are always normalized: Their most signifi- + /// cant digit is nonzero, unless the value is zero. Thus, ndigits is often + /// less than size. Figure 18.1 shows the layout of an 11-digit AP_T that is + /// equal to 751,702,468,129 on a little endian computer with 32-bit words + /// and 8-bit characters.. + sign: i8, + ndigits: u32, + /// ptr,len,cap + digits: [u8; N], +} +impl<const N: usize> const Eq for AP<N> {} +impl<const N: usize> const PartialEq for AP<N> { + 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 N: usize> const Default for AP<N> { + fn default() -> Self { + Self { sign: 1, ndigits: 1, digits: [0; N] } + } +} + +impl<const N: usize> Debug for AP<N> { + 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<const N: usize> Display for AP<N> { + 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<const N: usize> AP<N> { + 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(); + 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()); + } + pub 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() -> Self { + Self { sign: 1, ndigits: 1, digits: [0; N] } + } + const fn add<const N2: usize, const N3: usize>( + z: &mut Self, + x: &AP<N2>, + y: &AP<N3>, + ) { + 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<const N2: usize, const N3: usize>( + z: &mut Self, + x: &AP<N2>, + y: &AP<N3>, + ) { + 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<const N2: usize>(x: &Self, y: &AP<N2>) -> Ordering { + if x.ndigits != y.ndigits { + x.ndigits.cmp(&y.ndigits) + } else { + xp::cmp(x.ndigits, x.dgr(), y.dgr()) + } + } + const fn smsn<const N2: usize>(x: &Self, y: &AP<N2>) -> bool { + // x.sign == y.sign + (x.sign ^ y.sign) == 0 + } + pub const fn divmod<const N2: usize>( + x: &Self, + y: &AP<N2>, + ) -> (Self, AP<N2>) + where + [u8; N2 + N + 2]: Constructible, + { + assert!(!y.iszero()); + let mut q = Self::alloc(); + let mut r = AP::<N2>::alloc(); + xp::div( + x.ndigits, + q.dg(), + x.dgr(), + y.ndigits, + y.dgr(), + r.dg(), + AP::<{ N2 + N + 2 }>::alloc().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 + } + pub const fn mulmod<const N2: usize, const N3: usize>( + x: &Self, + y: &AP<N2>, + p: &AP<N3>, + ) -> AP<N3> + where + [(); N + N2]:, + [(); N3 + { N + N2 } + 2]:, + { + let xy: AP<{ N + N2 }> = x * y; + &xy % p + } + // pub const fn pow<const N2: usize>(&self, y: &AP<N2>) -> AP + // where + // [(); { N2 - (1 / 8) }]:, + // { + // 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.shr::<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_<const N2: usize>(x: &Self, y: &AP<N2>) -> Ordering { + if x.ndigits != y.ndigits { + x.ndigits.cmp(&y.ndigits) + } else { + xp::cmp(x.ndigits, x.dgr(), y.dgr()) + } + } +} + +// impl const Drop for AP { +// fn drop(&mut self) {} +// } + +impl<const N: usize> const Neg for AP<N> { + type Output = AP<N>; + + fn neg(mut self) -> Self::Output { + self.sign = if self.iszero() { 1 } else { -self.sign }; + self + } +} + +impl<const N: usize, const N2: usize> const Mul<&AP<N2>> for &AP<N> +where + [u8; N + N2]: Constructible, +{ + type Output = AP<{ N + N2 }>; + + fn mul(self, rhs: &AP<N2>) -> Self::Output { + let mut z = Self::Output::alloc(); + 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 N: usize, const N2: usize> const Add<&AP<N2>> for &AP<N> +where + [u8; N.max(N2) + 1]: Constructible, +{ + type Output = AP<{ N.max(N2) + 1 }>; + + fn add(self, rhs: &AP<N2>) -> Self::Output { + let mut z = AP::alloc(); + if AP::smsn(&self, &rhs) { + AP::add(&mut z, &self, &rhs); + z.sign = if z.iszero() { 1 } else { self.sign }; + } else if AP::cmp(self, rhs).is_gt() { + AP::sub(&mut z, self, rhs); + z.sign = if z.iszero() { 1 } else { self.sign }; + } else { + AP::sub(&mut z, rhs, self); + z.sign = if z.iszero() { 1 } else { -self.sign }; + } + z + } +} +impl<const N: usize, const N2: usize> const Sub<&AP<N2>> for &AP<N> +where + [u8; N.max(N2) + 1]: Constructible, +{ + type Output = AP<{ N.max(N2) + 1 }>; + + fn sub(self, rhs: &AP<N2>) -> Self::Output { + let mut z = AP::alloc(); + if !AP::smsn(self, rhs) { + AP::add(&mut z, self, rhs); + z.sign = if z.iszero() { 1 } else { self.sign }; + } else if AP::cmp(self, rhs).is_gt() { + AP::sub(&mut z, self, rhs); + z.sign = if z.iszero() { 1 } else { self.sign }; + } else { + AP::sub(&mut z, rhs, self); + z.sign = if z.iszero() { 1 } else { -self.sign }; + } + z + } +} +impl<const N: usize, const N2: usize> const Div<&AP<N2>> for &AP<N> +where + [u8; N2 + N + 2]: Constructible, +{ + type Output = AP<N>; + + fn div(self, rhs: &AP<N2>) -> Self::Output { + AP::divmod(self, rhs).0 + } +} + +impl<const N: usize, const N2: usize> const Rem<&AP<N2>> for &AP<N> +where + [u8; N2 + N + 2]: Constructible, +{ + type Output = AP<N2>; + + fn rem(self, rhs: &AP<N2>) -> Self::Output { + AP::divmod(self, rhs).1 + } +} +impl<const N: usize> AP<N> { + pub const fn shl<const S: usize>( + &self, + ) -> AP<{ N + (((S + 7) & !7) / 8) }> { + let mut z = AP::alloc(); + xp::shl(z.sz(), z.dg(), self.ndigits, self.dgr(), S as _, 0); + z.sign = self.sign; + z.normalize(z.sz()); + z + } +} + +// impl<const N: usize> Shl<u32> for AP<N> +// where +// [u8; 8 + N]: Constructible, +// { +// type Output = AP<{ 8 + N }>; + +// 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 N: usize> AP<N> { + pub const fn shr<const S: usize>(&self) -> AP<{ N - (S / 8) }> { + if S >= 8 * self.ndigits as usize { + return AP::new(0); + } + + let mut z = AP::alloc(); + let c = + xp::shr(z.sz(), z.dg(), self.ndigits, self.dgr(), S as _, 0); + + z.sign = if z.iszero() { 1 } else { self.sign }; + z.normalize(z.sz()); + z + } +} + +// impl<const N: usize> Shr<u32> for AP<N> { +// 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 $what:expr => &$and:expr => $fname:ident => $($for:ident)+) => { + $(impl<const N:usize> const $t<$for> for &AP<N> + where [u8; $what]: Constructible,[u8; $and]: Constructible, + { + type Output = AP<$what>; + fn $fname(self, other: $for) -> Self::Output { + let other = AP::<8>::new(other as _); + self.$fname(&other) + } + })+ + $(impl<const N:usize> const $t<$for> for AP<N> + where [u8; $what]: Constructible,[u8; $and]: Constructible, + { + type Output = AP<$what>; + fn $fname(self, other: $for) -> Self::Output { + let other = AP::<8>::new(other as _); + (&self).$fname(&other) + } + })+ + // $(impl const $t<$for> for AP { + // type Output = AP; + // fn $fname(self, other: $for) -> AP { + // let other = AP::new(other as _); + // (&self).$fname(&other) + // } + // })+ + }; +} +fni!(Add { N.max(8)+1 } => &0 => add => u64 u32 u16 u8 i128 i64 i32 i16 i8); +fni!(Mul { N + 8 } => &0 => mul => u64 u32 u16 u8 i128 i64 i32 i16 i8); +fni!(Div N => &{ 8 + N + 2} => div => u64 u32 u16 u8 i128 i64 i32 i16 i8); +fni!(Sub { N.max(8)+1} => &0 => sub => u64 u32 u16 u8 i128 i64 i32 i16 i8); +fni!(Rem { 8 } => &{ 8 + N + 2} => rem => u64 u32 u16 u8 i128 i64 i32 i16 i8); + +impl const PartialOrd for AP { + fn partial_cmp(&self, other: &Self) -> Option<Ordering> { + 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) + } + } +} |