#![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::string::*; #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::*; #[cfg(feature = "std")] use std::prelude::v1::*; use core::cmp::{Ordering, PartialEq, PartialOrd}; use core::convert::*; 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. /// /// Radix must be between 1 and 36, inclusive, with radix higher /// than 11 represented by A-Z /// /// Only alphanumeric characters are considered, so exponents and /// other forms are not parsed pub fn from_str_radix(s: T, radix: usize) -> BigInt { let input = s.to_string().to_ascii_uppercase(); let input = input.trim(); assert!( radix > 0 && radix <= 36, "Radix must be between 1 and 36, inclusive. Given radix: {}", radix ); // In base 1, number of place values = total value if radix == 1 { let mut raw_digits: Vec = Vec::with_capacity(input.len()); for char in input.chars() { match char { '1' => raw_digits.push(1), _ => continue, } } return BigInt::from(raw_digits.len()); } // If the number fits in a usize, try the easy way let easy_res = usize::from_str_radix(input, radix as u32); if easy_res.is_ok() { return BigInt::from(easy_res.unwrap()); } // TODO: consider parsing out the error, to tell if the // parsed result is valid for the base // Convert each digit to it's decimal representation let mut raw_digits: Vec = Vec::with_capacity(input.len()); for maybe_digit in input.chars() { match maybe_digit.to_digit(radix as u32) { Some(d) => raw_digits.push(d as usize), None => continue, } } // Calculate the decimal value by calculating the value // of each place value todo!(); } fn get_ceil_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 } } /// Normal primitive multiplication fn prim_mul(self, rhs: Self, digits: usize) -> Self { 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 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_ceil_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_ceil_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 { // This is the easy way, no additional borrowing or underflow let res = a - b - borrow; out.inner.push(res); borrow = 0; } else { // To prevent overflow, the max borrowed value is // usize::MAX (place-value - 1). The rest of the borrowed value // will be added on afterwords. // In base ten, this would be like: // 15 - 8 = (9 - 8) + (5 + 1) 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 { let input_digits = Self::get_ceil_digit_count(&self, &rhs); // Multiplication can result in twice the number of digits let out_digits = Self::get_ceil_digit_count(&self, &rhs) * 2; self.prim_mul(rhs, out_digits) } } 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, } } } impl PartialOrd for BigInt { fn partial_cmp(&self, other: &Self) -> Option { // The signs differ if self.sign != other.sign { // If the signs are different, the magnitude doesn't matter // unless the value is zero on both sides return if self.eq(&0) && other.eq(&0) { Some(Ordering::Equal) } else { self.sign.partial_cmp(&other.sign) }; } // Everything is the same if self.inner == other.inner { return Some(Ordering::Equal); } // The number of place values differs if self.inner.len() != other.inner.len() { return if self.inner.len() > other.inner.len() { Some(Ordering::Greater) } else { Some(Ordering::Less) }; } // At this point the sign is the same, and the number of place values is equal, // so compare the individual place values (from greatest to least) until they // are different. At this point, the digits can not all be equal. for i in (0usize..self.inner.len()).rev() { if self.inner[i] < other.inner[i] { return Some(Ordering::Less); } else if self.inner[i] > other.inner[i] { return Some(Ordering::Greater); } } unreachable!(); } } 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 { use core::usize::MAX; let target_radix: $s = (MAX as $s) + 1; let sign = if n < 0 { Sign::Negative } else { Sign::Positive }; let n = n.abs(); let mut quotient = n / target_radix; let mut rem = n % target_radix; if quotient == 0 { Self::from(rem as usize) } else { let mut inner: Vec = Vec::new(); inner.push(rem as usize); loop { rem = quotient % target_radix; quotient = quotient / target_radix; inner.push(rem as usize); if (quotient == 0) { break; } } BigInt { inner, sign, } } } } impl From<$u> for BigInt { /// Create a `BigInt` from an unsigned integer primitive fn from(n: $u) -> Self { use core::usize::MAX; let target_radix: $u = (MAX as $u) + 1; let mut quotient = n / target_radix; let mut rem = n % target_radix; if quotient == 0 { Self::from(rem as usize) } else { let mut inner: Vec = Vec::new(); inner.push(rem as usize); loop { rem = quotient % target_radix; quotient = quotient / target_radix; inner.push(rem as usize); if (quotient == 0) { break; } } BigInt { inner, sign: Sign::Positive } } } } )* }; } macro_rules! impl_ord_literal { ($($prim: ty),+) => { $( impl PartialEq<$prim> for BigInt { fn eq(&self, other: &$prim) -> bool { self == &BigInt::from(*other) } } impl PartialEq for $prim { fn eq(&self, other: &BigInt) -> bool { &BigInt::from(*self) == other } } impl PartialOrd<$prim> for BigInt { fn partial_cmp(&self, other: &$prim) -> Option { self.partial_cmp(&BigInt::from(*other)) } } impl PartialOrd for $prim { fn partial_cmp(&self, other: &BigInt) -> Option { (&BigInt::from(*self)).partial_cmp(other) } } )+ }; } #[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 = "64")] impl_from_larger!((i128, u128)); #[cfg(target_pointer_width = "64")] impl_from_smaller!((i8, u8), (i16, u16), (i32, u32), (i64, u64)); // Implement PartialEq and PartialOrd to compare against BigInt values impl_ord_literal!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128); #[cfg(test)] #[cfg(not(tarpaulin_include))] mod tests { use super::*; const RADIX: u128 = core::usize::MAX as u128 + 1; const I_RADIX: i128 = core::usize::MAX as i128 + 1; #[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 lots_of_leading = BigInt { inner: vec![1, 0, 0, 0, 0, 0, 0, 0, 0], sign: Positive, }; lots_of_leading.trim_zeros(); assert_eq!(BigInt::from(1), lots_of_leading); } #[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_partial_eq() { let a = 12345u16; let b = BigInt::from(a); assert!(a.eq(&b)); assert!(b.eq(&a)); } #[test] fn test_partial_ord() { let a = 12345u32; let b = BigInt::from(a); let c = 3u8; assert_eq!(a.partial_cmp(&b), Some(Ordering::Equal)); assert_eq!(c.partial_cmp(&b), Some(Ordering::Less)); assert_eq!(b.partial_cmp(&c), Some(Ordering::Greater)); assert!(big_int!(-32) < big_int!(3)); assert!(big_int!(3) > big_int!(-32)); assert!(big_int!(152) > big_int!(132)); assert_eq!(big_int!(123), big_int!(123)); } #[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] fn test_from_large_unsigned() { let big_num: u128 = 9 * RADIX + 8; let res = BigInt::from(big_num); assert_eq!(res.sign, Sign::Positive, "{:#?}", res); assert_eq!(res.inner[0], 8usize, "{:#?}", res); assert_eq!(res.inner[1], 9usize, "{:#?}", res); } #[test] fn test_from_large_signed() { let big_num: i128 = 2 * I_RADIX + 3; let res = BigInt::from(-big_num); assert_eq!(res.sign, Sign::Negative, "{:#?}", res); assert_eq!(res.inner[0], 3usize, "{:#?}", res); assert_eq!(res.inner[1], 2usize, "{:#?}", res); } #[test] #[should_panic] fn test_from_str_large() { let str = "ZYXWVUTSRQPONMLKJIHGFEDCBA987654321"; BigInt::from(str); } #[test] fn test_from_str_small() { let str = "012345"; let num = BigInt::from(str); assert_eq!(num.inner[0], 12345usize); } #[test] #[should_panic] fn test_from_string_large() { let str = String::from("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321"); BigInt::from(str); } #[test] fn test_from_string_small() { let str = String::from("012345"); let num = BigInt::from(str); assert_eq!(num.inner[0], 12345usize); } #[test] fn test_from_str_radix_1() { let s = "1".repeat(32); let num = BigInt::from_str_radix(s, 1); assert_eq!(num.inner[0], 32usize); } #[test] #[should_panic] fn test_from_str_radix_large() { BigInt::from_str_radix("ZYXWVUTSRQPONMLKJIHGFEDCBA987654321", 36); } #[test] fn test_from_str_radix_small() { let num = BigInt::from_str_radix("FEDCBA", 16); assert!(num.inner[0] > 0, "Number is not greater than 0"); assert!(num.inner[0] < usize::MAX, "Result is larger than usize"); assert_eq!(num.inner[0], 0xFEDCBAusize); } #[test] fn test_from_str_radix_lowercase() { let num = BigInt::from_str_radix("fedcba", 16); assert_eq!(num.inner[0], 0xFEDCBAusize); } }