Partially implement multiplication, code formatting
All checks were successful
timw4mail/rusty-numbers/pipeline/head This commit looks good
All checks were successful
timw4mail/rusty-numbers/pipeline/head This commit looks good
This commit is contained in:
parent
74744095f1
commit
f8b91531b9
@ -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
|
@ -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);
|
||||
|
||||
|
@ -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…
Reference in New Issue
Block a user