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.
|
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);
|
criterion_main!(benches);
|
||||||
|
|
||||||
|
@ -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]
|
||||||
|
Loading…
Reference in New Issue
Block a user