rusty-numbers/src/bigint.rs

169 lines
3.5 KiB
Rust

//! \[WIP\] Arbitrarily large integers
//!
//! Traits to implement:
//! * Add
//! * AddAssign
//! * Div
//! * DivAssign
//! * Mul
//! * MulAssign
//! * Neg
//! * Rem
//! * RemAssign
//! * Sub
//! * SubAssign
use crate::num::*;
#[derive(Clone, Debug)]
pub struct BigInt {
inner: Vec<usize>,
sign: Sign,
}
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;
#[cfg(target_pointer_width = "32")]
impl_from_smaller!(u8, u16, u32);
#[cfg(target_pointer_width = "32")]
static BITS:usize = 32;
#[cfg(target_pointer_width = "64")]
impl_from_smaller!(u8, u16, u32, u64);
#[cfg(target_pointer_width = "64")]
static BITS:usize = 64;
fn add(u: BigInt, v: BigInt) -> BigInt {
let mut out = BigInt::default();
let u_digits = u.inner.len();
let v_digits = v.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 = *u.inner.get(i).unwrap_or(&0usize);
let b = *v.inner.get(i).unwrap_or(&0usize);
let (res, overflowed) = a.overflowing_add(b);
// assert!(!overflowed, "Expected to overflow: {:#?}", (res, overflowed));
if overflowed {
if i == 0 {
out.inner[i] = res;
} else {
out.inner.push(res);
}
carry = core::usize::MAX - res;
} else {
if res < core::usize::MAX {
out.inner.push(res + carry);
carry = 0;
} else {
out.inner.push(0usize);
carry = 1;
}
carry = 0;
}
}
out
}
impl Default for BigInt {
fn default() -> Self {
Self {
inner: vec![0],
sign: Sign::Positive,
}
}
}
impl From<usize> for BigInt {
fn from(n: usize) -> Self {
Self {
inner: vec![n],
sign: Sign::Positive,
}
}
}
impl From<&str> for BigInt {
fn from(_: &str) -> Self {
unimplemented!()
}
}
impl From<String> for BigInt {
fn from(_: String) -> Self {
unimplemented!()
}
}
impl BigInt {
pub fn new() -> Self {
Self::default()
}
pub fn shrink_to_fit(&mut self) {
todo!();
}
pub fn from_str_radix<T: ToString>(s: T, radix: usize) {
todo!();
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sanity_checks() {
let int = BigInt::from(45u8);
assert_eq!(int.inner[0], 45usize)
}
#[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 = add(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");
// assert!(false, "{:#?} should have inner equal to {:?}", sum, core::u64::MAX as u128 + core::u64::MAX as u128);
}
}