#![allow(unused_variables)] //! \[WIP\] Arbitrarily large integers use crate::num::Sign::*; use crate::num::*; use core::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign, }; use core::usize; use std::convert::TryInto; #[derive(Clone, Debug, PartialEq)] pub struct BigInt { inner: Vec, sign: Sign, } impl Default for BigInt { fn default() -> Self { Self { inner: vec![0], sign: Sign::default(), } } } impl From for BigInt { fn from(n: usize) -> Self { Self { inner: vec![n], sign: Sign::default(), } } } 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 { /// Create a new Bigint, of value 0 /// /// The various `From` implementations are more useful in most cases pub fn new() -> Self { Self::default() } fn new_empty() -> Self { Self { inner: Vec::new(), sign: Sign::Positive, } } /// Create a new BigInt, with the specified inner capacity pub fn with_capacity(size: usize) -> Self { Self { inner: Vec::with_capacity(size), sign: Positive, } } /// Remove digits that are zero from the internal representation. /// /// Similar to 007 -> 7 in base 10 pub fn trim_zeros(&mut self) { let current_len = self.inner.len(); if current_len < 2 { return; } let mut trailing_zeros = 0usize; for val in self.inner.iter().rev() { if *val != 0 { break; } trailing_zeros += 1; } // Always keep at least one digit if trailing_zeros == current_len { trailing_zeros -= 1; } let new_len = current_len - trailing_zeros; self.inner.truncate(new_len); } /// Remove unused digits, and shrink the internal vector pub fn shrink_to_fit(&mut self) { self.trim_zeros(); self.inner.shrink_to_fit(); } /// Convert a `&str` or a `String` representing a number in the specified radix to a Bigint. /// /// For radix 10, use the `from` associated function instead. pub fn from_str_radix(s: T, radix: usize) -> BigInt { todo!(); } fn get_digit_count(a: &Self, b: &Self) -> usize { let a_digits = a.inner.len(); let b_digits = b.inner.len(); let digits = if b_digits > a_digits { b_digits } else { a_digits }; if digits > 0 { digits } else { 1 } } } impl Add for BigInt { type Output = Self; // @TODO: handle signs fn add(self, rhs: Self) -> Self::Output { if self.sign == Positive && rhs.sign == Negative { return self - -rhs; } let digits = Self::get_digit_count(&self, &rhs) + 1; let mut out = BigInt::with_capacity(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 res == 0 && !overflowed { out.inner.push(res + carry); carry = 0; continue; } if overflowed { 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; } } out.trim_zeros(); out } } impl Sub for BigInt { type Output = Self; // @TODO: handle signs fn sub(self, rhs: Self) -> Self::Output { let digits = Self::get_digit_count(&self, &rhs); let mut out = BigInt::with_capacity(digits); let mut borrow = 0usize; for i in 0..digits { let a = *self.inner.get(i).unwrap_or(&0usize); let b = *rhs.inner.get(i).unwrap_or(&0usize); if a >= borrow && (a - borrow) >= b { let res = a - b - borrow; out.inner.push(res); borrow = 0; } else { // To prevent subtraction overflow, the max borrowed // value is usize::MAX. The rest of the borrowed value // will be added on afterwords. // In base ten, this would be like: // 18 - 9 = 9-9 + 9 let rem = (a + 1) - borrow; let res = (core::usize::MAX - b) + rem; out.inner.push(res); borrow = 1; } } out.trim_zeros(); out } } impl Mul for BigInt { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { // Multiplication can result in twice the number of digits let digits = Self::get_digit_count(&self, &rhs) * 2; let mut out = BigInt::with_capacity(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); if a == 0 || b == 0 { out.inner.push(0); continue; } let (res, overflowed) = a.overflowing_mul(b); if overflowed { todo!() } else { match res.checked_add(carry) { Some(res) => { out.inner.push(res); carry = 0; } None => { // Well, we have to deal with overflow again todo!(); } } } } out.trim_zeros(); out } } impl Div for BigInt { type Output = Self; fn div(self, rhs: Self) -> Self::Output { todo!() } } impl Rem for BigInt { type Output = Self; fn rem(self, rhs: Self) -> Self::Output { todo!() } } 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; /// Flip the sign of the current `BigInt` value fn neg(mut self) -> Self::Output { self.sign = !self.sign; self } } impl Not for BigInt { type Output = Self; /// Do a bitwise negation of every digit's value 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, } } } macro_rules! impl_from_smaller { ($(($s: ty, $u: ty)),* ) => { $( impl From<$s> for BigInt { /// Create a `BigInt` from a signed integer primitive fn from(n: $s) -> Self { let sign = if n < 0 { Sign::Negative } else { Sign::Positive }; let n = n.abs(); let raw: usize = <$s>::try_into(n).unwrap(); Self { inner: vec![raw], sign, } } } impl From<$u> for BigInt { /// Create a `BigInt` from an unsigned integer primitive fn from(n: $u) -> Self { let mut new = Self::new_empty(); new.inner.push(n as usize); new } } )* } } macro_rules! impl_from_larger { ($(($s: ty, $u: ty)),* ) => { $( impl From<$s> for BigInt { /// Create a `BigInt` from a signed integer primitive fn from(n: $s) -> Self { todo!(); } } impl From<$u> for BigInt { /// Create a `BigInt` from an unsigned integer primitive fn from(n: $u) -> Self { use core::usize::MAX; let base_usize_value = n / MAX as $u; let rem = n % MAX as $u; if base_usize_value == 0 { Self::from(rem as usize) } else { todo!(); } } } )* }; } #[cfg(target_pointer_width = "32")] impl_from_larger!((i64, u64), (i128, u128)); #[cfg(target_pointer_width = "32")] impl_from_smaller!((i8, u8), (i16, u16), (i32, u32)); #[cfg(target_pointer_width = "32")] static BITS: usize = 32; #[cfg(target_pointer_width = "64")] impl_from_larger!((i128, u128)); #[cfg(target_pointer_width = "64")] impl_from_smaller!((i8, u8), (i16, u16), (i32, u32), (i64, u64)); #[cfg(target_pointer_width = "64")] static BITS: usize = 64; #[cfg(test)] #[cfg_attr(tarpaulin, skip)] mod tests { use super::*; #[test] fn sanity_checks() { let int = BigInt::from(45u8); assert_eq!(int.inner[0], 45usize) } #[test] fn test_trim_zeros() { let mut lotsoftrailing = BigInt { inner: vec![1, 0, 0, 0, 0, 0, 0, 0, 0], sign: Positive, }; lotsoftrailing.trim_zeros(); assert_eq!(BigInt::from(1), lotsoftrailing); } #[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_sub() { let a = BigInt::from(core::usize::MAX); let b = BigInt::from(core::u16::MAX); let diff = a - b; assert_eq!( diff.clone().inner[0], core::usize::MAX - core::u16::MAX as usize ); assert_eq!(diff.inner.len(), 1); } #[test] fn test_sub_borrow() { let a = BigInt { inner: vec![0, 1], sign: Positive, }; let b = BigInt::from(2); let diff = a - b; assert_eq!(diff.clone().inner.len(), 1, "{:#?}", diff.clone()); assert_eq!(diff.inner[0], core::usize::MAX - 1); } #[test] fn test_sub_assign() { let mut a = BigInt { inner: vec![1, 0, 1], sign: Positive, }; let b = BigInt::from(2); a -= b; assert_eq!(a.inner, vec![core::usize::MAX, core::usize::MAX]); } #[test] fn test_zeros() { let a = BigInt::new(); let b = BigInt::new(); let c = a.clone() - b.clone(); assert_eq!(a.clone(), b.clone()); assert_eq!(c, a.clone()); let c = a.clone() + b.clone(); assert_eq!(a.clone(), b.clone()); assert_eq!(c, a.clone()); } #[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"); } #[test] fn test_from() { // Signed numbers assert_eq!(-BigInt::from(2), BigInt::from(-2)); // Larger than usize assert_eq!(BigInt::from(45u128), BigInt::from(45usize)); } }