Do you wish to register an account?
Browse Source

Partially implement multiplication, code formatting

master
Timothy Warren 8 months ago
parent
commit
f8b91531b9
3 changed files with 75 additions and 31 deletions
  1. +7
    -0
      README.md
  2. +6
    -2
      benches/stock_functions.rs
  3. +62
    -29
      src/bigint.rs

+ 7
- 0
README.md 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

+ 6
- 2
benches/stock_functions.rs 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);


+ 62
- 29
src/bigint.rs 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]


Loading…
Cancel
Save