//! \[WIP\] Arbitrarily large integers //! //! Traits to implement: //! * Add //! * AddAssign //! * Div //! * DivAssign //! * Mul //! * MulAssign //! * Neg //! * Rem //! * RemAssign //! * Sub //! * SubAssign use crate::num::*; #[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; fn add(u: BigInt, v: BigInt) -> BigInt { let mut out = BigInt::default(); let u_digits = u.inner.len(); let v_digits = v.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 = *u.inner.get(i).unwrap_or(&0usize); let b = *v.inner.get(i).unwrap_or(&0usize); let (res, overflowed) = a.overflowing_add(b); // assert!(!overflowed, "Expected to overflow: {:#?}", (res, overflowed)); if overflowed { if i == 0 { out.inner[i] = res; } else { out.inner.push(res); } carry = core::usize::MAX - res; } else { if res < core::usize::MAX { out.inner.push(res + carry); carry = 0; } else { out.inner.push(0usize); carry = 1; } carry = 0; } } out } 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(_: &str) -> Self { unimplemented!() } } impl From for BigInt { fn from(_: String) -> Self { unimplemented!() } } 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) { todo!(); } } #[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 = add(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"); // assert!(false, "{:#?} should have inner equal to {:?}", sum, core::u64::MAX as u128 + core::u64::MAX as u128); } }