//! \[WIP\] Arbitrarily large integers //! //! Traits to implement: //! * Neg //! * Rem //! * RemAssign //! * Sub //! * SubAssign use crate::num::*; use core::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign, }; #[derive(Clone, Debug)] pub struct BigInt { inner: Vec, sign: Sign, } macro_rules! impl_from_smaller { ($($Type: ty),* ) => { $( impl From<$Type> for BigInt { fn from(n: $Type) -> Self { let mut new = Self::default(); new.inner[0] = n as usize; new } } )* } } #[cfg(target_pointer_width = "16")] impl_from_smaller!(u8, u16); #[cfg(target_pointer_width = "16")] static BITS:usize = 16; #[cfg(target_pointer_width = "32")] impl_from_smaller!(u8, u16, u32); #[cfg(target_pointer_width = "32")] static BITS:usize = 32; #[cfg(target_pointer_width = "64")] impl_from_smaller!(u8, u16, u32, u64); #[cfg(target_pointer_width = "64")] static BITS:usize = 64; impl Default for BigInt { fn default() -> Self { Self { inner: vec![0], sign: Sign::Positive, } } } impl From for BigInt { fn from(n: usize) -> Self { Self { inner: vec![n], sign: Sign::Positive, } } } impl From<&str> for BigInt { fn from(s: &str) -> Self { Self::from_str_radix(s, 10) } } impl From for BigInt { fn from(s: String) -> Self { Self::from_str_radix(s, 10) } } impl BigInt { pub fn new() -> Self { Self::default() } pub fn shrink_to_fit(&mut self) { todo!(); } pub fn from_str_radix(s: T, radix: usize) -> BigInt { todo!(); } } impl Add for BigInt { type Output = Self; fn add(self, rhs: Self) -> Self::Output { // @TODO: handle signs let mut out = BigInt::default(); let u_digits = self.inner.len(); let v_digits = rhs.inner.len(); let digits = if v_digits > u_digits { v_digits } else { u_digits }; let mut carry = 0usize; for i in 0..=digits { let a = *self.inner.get(i).unwrap_or(&0usize); let b = *rhs.inner.get(i).unwrap_or(&0usize); let (res, overflowed) = a.overflowing_add(b); if overflowed { if i == 0 { out.inner[i] = res + carry; } else { out.inner.push(res + carry); } carry = 1; } else { if res < core::usize::MAX { out.inner.push(res + carry); carry = 0; } else { out.inner.push(0usize); carry = 1; } carry = 0; } } out } } impl Sub for BigInt { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { unimplemented!() } } impl Mul for BigInt { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { unimplemented!() } } impl Div for BigInt { type Output = Self; fn div(self, rhs: Self) -> Self::Output { unimplemented!() } } impl Rem for BigInt { type Output = Self; fn rem(self, rhs: Self) -> Self::Output { unimplemented!() } } impl AddAssign for BigInt { fn add_assign(&mut self, rhs: Self) { *self = self.clone() + rhs; } } impl SubAssign for BigInt { fn sub_assign(&mut self, rhs: Self) { *self = self.clone() - rhs; } } impl MulAssign for BigInt { fn mul_assign(&mut self, rhs: Self) { *self = self.clone() * rhs; } } impl DivAssign for BigInt { fn div_assign(&mut self, rhs: Self) { *self = self.clone() / rhs; } } impl RemAssign for BigInt { fn rem_assign(&mut self, rhs: Self) { *self = self.clone() % rhs; } } impl Neg for BigInt { type Output = Self; fn neg(self) -> Self::Output { let mut output = self.clone(); output.sign = !output.sign; output } } impl Not for BigInt { type Output = Self; fn not(self) -> Self::Output { let mut flipped: Vec = Vec::with_capacity(self.inner.len()); for val in self.inner.iter() { let rev = !*val; flipped.push(rev); } BigInt { sign: self.sign, inner: flipped, } } } #[cfg(test)] mod tests { use super::*; #[test] fn sanity_checks() { let int = BigInt::from(45u8); assert_eq!(int.inner[0], 45usize) } #[test] fn test_add() { // MAX is 2^Bitsize - 1, // so the sum should be // [MAX -1, 1] // Compare base 10: 9 + 9 = 18 let a = BigInt::from(core::usize::MAX); let b = BigInt::from(core::usize::MAX); let sum = a + b; assert_eq!( sum.inner[0], core::usize::MAX - 1, "least significant place should be MAX - 1" ); assert_eq!(sum.inner[1], 1usize, "most significant place should be 1"); let a = BigInt::from(core::usize::MAX); let b = BigInt::from(1usize); let sum = a + b; assert_eq!(sum.inner[0], 0usize); assert_eq!(sum.inner[1], 1usize); } #[test] fn test_not() { let a = BigInt::from(0u8); let b = !a; assert_eq!(b.inner[0], core::usize::MAX); } #[test] fn test_add_assign() { let mut a = BigInt::from(core::usize::MAX); let b = BigInt::from(core::usize::MAX); a += b; assert_eq!( a.inner[0], core::usize::MAX - 1, "least significant place should be MAX - 1" ); assert_eq!(a.inner[1], 1usize, "most significant place should be 1"); } }