Partially implement multiplication, code formatting
All checks were successful
timw4mail/rusty-numbers/pipeline/head This commit looks good

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.
[![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);

View File

@ -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]