From f8b91531b93a66ee68ac3ea68b8f626f5edf9830 Mon Sep 17 00:00:00 2001 From: Timothy Warren Date: Fri, 13 Mar 2020 14:17:25 -0400 Subject: [PATCH] Partially implement multiplication, code formatting --- README.md | 7 +++ benches/stock_functions.rs | 8 +++- src/bigint.rs | 91 ++++++++++++++++++++++++++------------ 3 files changed, 75 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index cd4e565..beba51e 100644 --- a/README.md +++ b/README.md @@ -2,3 +2,10 @@ Playing around with numeric types in Rust. +[![Build Status](https://jenkins.timshome.page/buildStatus/icon?job=timw4mail%2Frusty-numbers%2Fmaster)](https://jenkins.timshome.page/job/timw4mail/job/rusty-numbers/job/master/) + +## Components + +* Rational (fraction) type, which overloads arithmatic operators +* Various fibonacci/factorial implementations for native numeric types +* BigInt (high precision integer) type, overloading arithmatic operators \ No newline at end of file diff --git a/benches/stock_functions.rs b/benches/stock_functions.rs index 387442f..c4e7cce 100644 --- a/benches/stock_functions.rs +++ b/benches/stock_functions.rs @@ -102,6 +102,10 @@ mod sf { } } -criterion_group!(benches, sf::bench_factorial, sf::bench_fibonacci, sf::bench_gcd); +criterion_group!( + benches, + sf::bench_factorial, + sf::bench_fibonacci, + sf::bench_gcd +); criterion_main!(benches); - diff --git a/src/bigint.rs b/src/bigint.rs index 1e6cf67..e5ebd37 100644 --- a/src/bigint.rs +++ b/src/bigint.rs @@ -1,7 +1,7 @@ #![allow(unused_variables)] //! \[WIP\] Arbitrarily large integers -use crate::num::*; use crate::num::Sign::*; +use crate::num::*; use core::ops::{ Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign, }; @@ -59,19 +59,27 @@ impl BigInt { } } + /// 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 + return; } let mut trailing_zeros = 0usize; for val in self.inner.iter().rev() { if *val != 0 { - break + break; } trailing_zeros += 1; @@ -121,15 +129,14 @@ impl BigInt { impl Add for BigInt { type Output = Self; + // @TODO: handle signs fn add(self, rhs: Self) -> Self::Output { - // @TODO: handle signs if self.sign == Positive && rhs.sign == Negative { return self - -rhs; } - let mut out = BigInt::new_empty(); - 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 { @@ -164,11 +171,10 @@ impl Add for BigInt { impl Sub for BigInt { type Output = Self; + // @TODO: handle signs fn sub(self, rhs: Self) -> Self::Output { - // @TODO: handle signs - let mut out = BigInt::new_empty(); - let digits = Self::get_digit_count(&self, &rhs); + let mut out = BigInt::with_capacity(digits); let mut borrow = 0usize; for i in 0..digits { @@ -180,7 +186,7 @@ impl Sub for BigInt { out.inner.push(res); borrow = 0; - } else { + } else { // To prevent subtraction overflow, the max borrowed // value is usize::MAX. The rest of the borrowed value // will be added on afterwords. @@ -204,7 +210,41 @@ impl Mul for BigInt { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { - todo!() + // 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 } } @@ -258,11 +298,10 @@ impl Neg for BigInt { type Output = Self; /// Flip the sign of the current `BigInt` value - fn neg(self) -> Self::Output { - let mut output = self.clone(); - output.sign = !output.sign; + fn neg(mut self) -> Self::Output { + self.sign = !self.sign; - output + self } } @@ -349,14 +388,14 @@ 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; +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; +static BITS: usize = 64; #[cfg(test)] #[cfg_attr(tarpaulin, skip)] @@ -373,7 +412,7 @@ mod tests { fn test_trim_zeros() { let mut lotsoftrailing = BigInt { inner: vec![1, 0, 0, 0, 0, 0, 0, 0, 0], - sign: Positive + sign: Positive, }; lotsoftrailing.trim_zeros(); @@ -423,32 +462,26 @@ mod tests { fn test_sub_borrow() { let a = BigInt { inner: vec![0, 1], - sign: Positive + 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 - ); + 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 + 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] - ); + assert_eq!(a.inner, vec![core::usize::MAX, core::usize::MAX]); } #[test]