rusty-numbers/src/bigint.rs

289 lines
5.9 KiB
Rust
Raw Normal View History

//! \[WIP\] Arbitrarily large integers
2020-02-12 23:10:08 -05:00
//!
//! Traits to implement:
//! * Neg
//! * Rem
//! * RemAssign
//! * Sub
//! * SubAssign
use crate::num::*;
use core::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign,
};
2020-02-12 22:29:57 -05:00
#[derive(Clone, Debug)]
2020-02-12 22:29:57 -05:00
pub struct BigInt {
inner: Vec<usize>,
2020-02-12 23:10:08 -05:00
sign: Sign,
2020-02-12 22:29:57 -05:00
}
2020-03-03 16:33:21 -05:00
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;
2020-03-04 09:19:33 -05:00
#[cfg(target_pointer_width = "32")]
impl_from_smaller!(u8, u16, u32);
2020-03-03 16:33:21 -05:00
#[cfg(target_pointer_width = "32")]
static BITS:usize = 32;
2020-03-04 09:19:33 -05:00
#[cfg(target_pointer_width = "64")]
impl_from_smaller!(u8, u16, u32, u64);
2020-03-03 16:33:21 -05:00
#[cfg(target_pointer_width = "64")]
static BITS:usize = 64;
2020-02-12 22:29:57 -05:00
impl Default for BigInt {
fn default() -> Self {
Self {
2020-03-03 16:33:21 -05:00
inner: vec![0],
2020-02-12 23:10:08 -05:00
sign: Sign::Positive,
2020-02-12 22:29:57 -05:00
}
}
}
2020-03-03 16:33:21 -05:00
impl From<usize> for BigInt {
fn from(n: usize) -> Self {
Self {
inner: vec![n],
sign: Sign::Positive,
2020-02-12 22:29:57 -05:00
}
}
}
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)
}
}
2020-02-12 23:10:08 -05:00
impl BigInt {
2020-02-13 17:13:25 -05:00
pub fn new() -> Self {
Self::default()
}
2020-02-24 16:30:59 -05:00
pub fn shrink_to_fit(&mut self) {
todo!();
}
pub fn from_str_radix<T: ToString>(s: T, radix: usize) -> BigInt {
2020-02-12 22:29:57 -05:00
todo!();
}
}
impl Add for BigInt {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
2020-03-05 16:24:33 -05:00
// @TODO: handle signs
let mut out = BigInt::default();
let u_digits = self.inner.len();
let v_digits = rhs.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 = *self.inner.get(i).unwrap_or(&0usize);
let b = *rhs.inner.get(i).unwrap_or(&0usize);
let (res, overflowed) = a.overflowing_add(b);
if overflowed {
if i == 0 {
2020-03-05 16:24:33 -05:00
out.inner[i] = res + carry;
} else {
2020-03-05 16:24:33 -05:00
out.inner.push(res + carry);
}
2020-03-05 16:24:33 -05:00
carry = 1;
} else {
if res < core::usize::MAX {
out.inner.push(res + carry);
carry = 0;
} else {
out.inner.push(0usize);
carry = 1;
}
carry = 0;
}
}
out
}
}
impl Sub for BigInt {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
unimplemented!()
}
}
impl Mul for BigInt {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
unimplemented!()
}
}
impl Div for BigInt {
type Output = Self;
fn div(self, rhs: Self) -> Self::Output {
unimplemented!()
}
}
impl Rem for BigInt {
type Output = Self;
fn rem(self, rhs: Self) -> Self::Output {
unimplemented!()
}
}
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;
fn neg(self) -> Self::Output {
let mut output = self.clone();
output.sign = !output.sign;
output
}
}
2020-03-05 09:20:02 -05:00
impl Not for BigInt {
type Output = Self;
fn not(self) -> Self::Output {
let mut flipped: Vec<usize> = Vec::with_capacity(self.inner.len());
2020-03-05 16:24:33 -05:00
for val in self.inner.iter() {
let rev = !*val;
flipped.push(rev);
2020-03-05 09:20:02 -05:00
}
BigInt {
sign: self.sign,
inner: flipped,
}
}
}
2020-02-12 22:29:57 -05:00
#[cfg(test)]
2020-02-24 16:30:59 -05:00
mod tests {
use super::*;
#[test]
fn sanity_checks() {
2020-03-03 16:33:21 -05:00
let int = BigInt::from(45u8);
assert_eq!(int.inner[0], 45usize)
2020-02-24 16:30:59 -05:00
}
2020-03-03 16:33:21 -05:00
2020-03-04 09:19:33 -05:00
#[test]
2020-03-03 16:33:21 -05:00
fn test_add() {
2020-03-04 09:19:33 -05:00
// 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);
2020-03-03 16:33:21 -05:00
let sum = a + b;
2020-03-03 16:33:21 -05:00
assert_eq!(
sum.inner[0],
core::usize::MAX - 1,
"least significant place should be MAX - 1"
);
2020-03-04 09:19:33 -05:00
assert_eq!(sum.inner[1], 1usize, "most significant place should be 1");
2020-03-05 09:20:02 -05:00
2020-03-05 16:24:33 -05:00
let a = BigInt::from(core::usize::MAX);
2020-03-05 09:20:02 -05:00
let b = BigInt::from(1usize);
let sum = a + b;
assert_eq!(sum.inner[0], 0usize);
2020-03-05 16:24:33 -05:00
assert_eq!(sum.inner[1], 1usize);
}
#[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;
2020-03-04 09:19:33 -05:00
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");
2020-03-04 09:19:33 -05:00
}
2020-02-24 16:30:59 -05:00
}