Partially implement multiplication, code formatting
timw4mail/rusty-numbers/pipeline/head This commit looks good Details

This commit is contained in:
Timothy Warren 2020-03-13 14:17:25 -04:00
parent 74744095f1
commit f8b91531b9
3 changed files with 75 additions and 31 deletions

View File

@ -2,3 +2,10 @@
Playing around with numeric types in Rust. 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

View File

@ -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); criterion_main!(benches);

View File

@ -1,7 +1,7 @@
#![allow(unused_variables)] #![allow(unused_variables)]
//! \[WIP\] Arbitrarily large integers //! \[WIP\] Arbitrarily large integers
use crate::num::*;
use crate::num::Sign::*; use crate::num::Sign::*;
use crate::num::*;
use core::ops::{ use core::ops::{
Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub, SubAssign, 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. /// Remove digits that are zero from the internal representation.
/// ///
/// Similar to 007 -> 7 in base 10 /// Similar to 007 -> 7 in base 10
pub fn trim_zeros(&mut self) { pub fn trim_zeros(&mut self) {
let current_len = self.inner.len(); let current_len = self.inner.len();
if current_len < 2 { if current_len < 2 {
return return;
} }
let mut trailing_zeros = 0usize; let mut trailing_zeros = 0usize;
for val in self.inner.iter().rev() { for val in self.inner.iter().rev() {
if *val != 0 { if *val != 0 {
break break;
} }
trailing_zeros += 1; trailing_zeros += 1;
@ -121,15 +129,14 @@ impl BigInt {
impl Add for BigInt { impl Add for BigInt {
type Output = Self; type Output = Self;
// @TODO: handle signs
fn add(self, rhs: Self) -> Self::Output { fn add(self, rhs: Self) -> Self::Output {
// @TODO: handle signs
if self.sign == Positive && rhs.sign == Negative { if self.sign == Positive && rhs.sign == Negative {
return self - -rhs; return self - -rhs;
} }
let mut out = BigInt::new_empty();
let digits = Self::get_digit_count(&self, &rhs) + 1; let digits = Self::get_digit_count(&self, &rhs) + 1;
let mut out = BigInt::with_capacity(digits);
let mut carry = 0usize; let mut carry = 0usize;
for i in 0..digits { for i in 0..digits {
@ -164,11 +171,10 @@ impl Add for BigInt {
impl Sub for BigInt { impl Sub for BigInt {
type Output = Self; type Output = Self;
// @TODO: handle signs
fn sub(self, rhs: Self) -> Self::Output { 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 digits = Self::get_digit_count(&self, &rhs);
let mut out = BigInt::with_capacity(digits);
let mut borrow = 0usize; let mut borrow = 0usize;
for i in 0..digits { for i in 0..digits {
@ -180,7 +186,7 @@ impl Sub for BigInt {
out.inner.push(res); out.inner.push(res);
borrow = 0; borrow = 0;
} else { } else {
// To prevent subtraction overflow, the max borrowed // To prevent subtraction overflow, the max borrowed
// value is usize::MAX. The rest of the borrowed value // value is usize::MAX. The rest of the borrowed value
// will be added on afterwords. // will be added on afterwords.
@ -204,7 +210,41 @@ impl Mul for BigInt {
type Output = Self; type Output = Self;
fn mul(self, rhs: Self) -> Self::Output { 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; type Output = Self;
/// Flip the sign of the current `BigInt` value /// Flip the sign of the current `BigInt` value
fn neg(self) -> Self::Output { fn neg(mut self) -> Self::Output {
let mut output = self.clone(); self.sign = !self.sign;
output.sign = !output.sign;
output self
} }
} }
@ -349,14 +388,14 @@ impl_from_larger!((i64, u64), (i128, u128));
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
impl_from_smaller!((i8, u8), (i16, u16), (i32, u32)); impl_from_smaller!((i8, u8), (i16, u16), (i32, u32));
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
static BITS:usize = 32; static BITS: usize = 32;
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
impl_from_larger!((i128, u128)); impl_from_larger!((i128, u128));
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
impl_from_smaller!((i8, u8), (i16, u16), (i32, u32), (i64, u64)); impl_from_smaller!((i8, u8), (i16, u16), (i32, u32), (i64, u64));
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
static BITS:usize = 64; static BITS: usize = 64;
#[cfg(test)] #[cfg(test)]
#[cfg_attr(tarpaulin, skip)] #[cfg_attr(tarpaulin, skip)]
@ -373,7 +412,7 @@ mod tests {
fn test_trim_zeros() { fn test_trim_zeros() {
let mut lotsoftrailing = BigInt { let mut lotsoftrailing = BigInt {
inner: vec![1, 0, 0, 0, 0, 0, 0, 0, 0], inner: vec![1, 0, 0, 0, 0, 0, 0, 0, 0],
sign: Positive sign: Positive,
}; };
lotsoftrailing.trim_zeros(); lotsoftrailing.trim_zeros();
@ -423,32 +462,26 @@ mod tests {
fn test_sub_borrow() { fn test_sub_borrow() {
let a = BigInt { let a = BigInt {
inner: vec![0, 1], inner: vec![0, 1],
sign: Positive sign: Positive,
}; };
let b = BigInt::from(2); let b = BigInt::from(2);
let diff = a - b; let diff = a - b;
assert_eq!(diff.clone().inner.len(), 1, "{:#?}", diff.clone()); assert_eq!(diff.clone().inner.len(), 1, "{:#?}", diff.clone());
assert_eq!( assert_eq!(diff.inner[0], core::usize::MAX - 1);
diff.inner[0],
core::usize::MAX - 1
);
} }
#[test] #[test]
fn test_sub_assign() { fn test_sub_assign() {
let mut a = BigInt { let mut a = BigInt {
inner: vec![1,0,1], inner: vec![1, 0, 1],
sign: Positive sign: Positive,
}; };
let b = BigInt::from(2); let b = BigInt::from(2);
a -= b; a -= b;
assert_eq!( assert_eq!(a.inner, vec![core::usize::MAX, core::usize::MAX]);
a.inner,
vec![core::usize::MAX, core::usize::MAX]
);
} }
#[test] #[test]