#![allow(unused_variables)] //! \[WIP\] Arbitrarily large integers use crate::num::Sign::*; use crate::num::*; #[cfg(all(feature = "alloc", not(feature = "std")))] extern crate alloc; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::*; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::string::*; #[cfg(feature = "std")] use std::prelude::v1::*; use core::convert::TryInto; use core::mem::replace; use core::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign, }; use core::usize; #[derive(Clone, Debug, PartialEq)] pub struct BigInt { inner: Vec, sign: Sign, } /// Create a [BigInt](bigint/struct.BigInt.html) type with signed or unsigned number literals #[macro_export] macro_rules! big_int { ($w:literal) => { $crate::bigint::BigInt::from($w) }; (-$x:literal) => { $crate::bigint::BigInt::from(-$x) }; } 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(); if a_digits == 0 && b_digits == 0 { return 1; } if b_digits > a_digits { b_digits } else { a_digits } } /// Determine the output sign given the two input signs and operation fn get_sign(a: Self, b: Self, op: FracOp) -> Sign { // -a + -b = -c if op == FracOp::Addition && a.sign == Negative && b.sign == Negative { return Negative; } // a - -b = c if op == FracOp::Subtraction && a.sign == Positive && b.sign == Negative { return Positive; } if a.sign != b.sign { Negative } else { Positive } } } impl Add for BigInt { type Output = Self; fn add(self, rhs: Self) -> Self::Output { // If the sign of one input differs, // subtraction is equivalent if self.sign == Negative && rhs.sign == Positive { return rhs - -self; } else 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.sign = Self::get_sign(self, rhs, FracOp::Addition); out.trim_zeros(); out } } impl Sub for BigInt { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { let digits = Self::get_digit_count(&self, &rhs); let mut out = BigInt::with_capacity(digits); // Handle cases where addition makes more sense if self.sign == Positive && rhs.sign == Negative { return self + -rhs; } else if self.sign == Negative && rhs.sign == Positive { return -(rhs + -self); } 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.sign = Self::get_sign(self, rhs, FracOp::Subtraction); 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 { let (res, overflowed) = res.overflowing_add(carry); out.inner.push(res); carry = if overflowed { 1 } else { 0 }; } } out.sign = Self::get_sign(self, rhs, FracOp::Other); out.shrink_to_fit(); 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) { let this = replace(self, BigInt::new()); *self = this + rhs; } } impl SubAssign for BigInt { fn sub_assign(&mut self, rhs: Self) { let this = replace(self, BigInt::new()); *self = this - rhs; } } impl MulAssign for BigInt { fn mul_assign(&mut self, rhs: Self) { let this = replace(self, BigInt::new()); *self = this * rhs; } } impl DivAssign for BigInt { fn div_assign(&mut self, rhs: Self) { let this = replace(self, BigInt::new()); *self = this / rhs; } } impl RemAssign for BigInt { fn rem_assign(&mut self, rhs: Self) { let this = replace(self, BigInt::new()); *self = this % 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_macro() { let a = big_int!(75); let b = BigInt::from(75); assert_eq!(a, b); let a = big_int!(-75); let b = BigInt::from(-75); assert_eq!(a, b); } #[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); let a = BigInt::from(10); let b = -BigInt::from(5); let sum = a + b; assert_eq!(sum.inner[0], 5usize); assert_eq!(sum.sign, Positive); let a = -BigInt::from(5); let b = BigInt::from(10); let sum = a + b; assert_eq!(sum.inner[0], 5usize); assert_eq!(sum.sign, Positive); } #[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_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); let a = BigInt::from(5); let b = -BigInt::from(3); let diff = a - b; assert_eq!(diff.sign, Positive); assert_eq!(diff.inner[0], 8usize); let a = -BigInt::from(5); let b = BigInt::from(3); let diff = a - b; assert_eq!(diff.sign, Negative); assert_eq!(diff.inner[0], 8usize); } #[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_mul() { let a = BigInt::from(65536); let b = BigInt::from(4); let product = a * b; assert_eq!(product.inner[0], 65536usize * 4); } #[test] fn test_mul_signs() { let a = BigInt::from(2); let b = BigInt::from(-2); let product = a * b; assert_eq!(product.inner[0], 4usize); assert_eq!(product.sign, Negative); let a = -BigInt::from(2); let b = BigInt::from(2); let product = a * b; assert_eq!(product.inner[0], 4usize); assert_eq!(product.sign, Negative); let a = BigInt::from(-2); let b = BigInt::from(-2); let product = a * b; assert_eq!(product.inner[0], 4usize); assert_eq!(product.sign, Positive); let a = BigInt::from(2); let b = BigInt::from(2); let product = a * b; assert_eq!(product.inner[0], 4usize); assert_eq!(product.sign, Positive); } #[test] #[should_panic] fn test_mul_overflow() { let a = BigInt::from(core::usize::MAX); let b = BigInt::from(5); let product = a * b; } #[test] #[should_panic] fn test_mul_assign_overflow() { let mut a = BigInt::from(core::usize::MAX); let b = BigInt::from(5); a *= b; } #[test] #[should_panic] fn test_div() { let a = BigInt::from(128); let b = BigInt::from(32); let quotient = a / b; } #[test] #[should_panic] fn test_div_assign() { let mut a = BigInt::from(128); let b = BigInt::from(32); a /= b; } #[test] #[should_panic] fn test_rem() { let a = BigInt::from(5); let b = BigInt::from(2); let rem = a % b; } #[test] #[should_panic] fn test_rem_assign() { let mut a = BigInt::from(5); let b = BigInt::from(2); a %= b; } #[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_from() { // Signed numbers assert_eq!(-BigInt::from(2), BigInt::from(-2)); // Larger than usize assert_eq!(BigInt::from(45u128), BigInt::from(45usize)); } #[test] #[should_panic] fn test_from_large_unsigned() { BigInt::from(core::u128::MAX); } #[test] #[should_panic] fn test_from_large_signed() { BigInt::from(128i128); } #[test] #[should_panic] fn test_from_str() { let str = "012345"; BigInt::from(str); } #[test] #[should_panic] fn test_from_string() { let str = String::from("012345"); BigInt::from(str); } #[test] #[should_panic] fn test_from_str_radix() { BigInt::from_str_radix("123456", 16); } }