rusty-numbers/src/bigint.rs

533 lines
13 KiB
Rust

#![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<usize>,
sign: Sign,
}
impl Default for BigInt {
fn default() -> Self {
Self {
inner: vec![0],
sign: Sign::default(),
}
}
}
impl From<usize> 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<String> 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<T: ToString>(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<usize> = 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));
}
}