Pass cargo check and tests

This commit is contained in:
Timothy Warren 2020-02-13 17:13:25 -05:00
parent 421d548082
commit 23d0ab75ec
4 changed files with 202 additions and 46 deletions

View File

@ -34,7 +34,7 @@ impl<T: Unsigned> From<T> for BigInt {
let mut new = Self::default(); let mut new = Self::default();
if n > T::max_value() { if n > T::max_value() {
new.inner = BigInt::split(n); new.split(n);
} }
new new
@ -42,24 +42,21 @@ impl<T: Unsigned> From<T> for BigInt {
} }
impl BigInt { impl BigInt {
pub fn new() -> Self {
Self::default()
}
/// Split an unsigned number into BigInt parts /// Split an unsigned number into BigInt parts
fn split<T: Unsigned>(num: T) -> Vec<usize> { fn split<T: Unsigned>(&mut self, num: T) -> Vec<usize> {
// Pretty easy if you don't actually need to split the value! // Pretty easy if you don't actually need to split the value!
if num < T::max_value() { if num < T::max_value() {
return vec![T::into()]; todo!();
// return vec![num as usize];
} }
todo!(); todo!();
} }
} }
impl BigInt {
pub fn new() -> Self {
Self::default()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {}
}

View File

@ -1,25 +1,64 @@
#![forbid(unsafe_code)] #![forbid(unsafe_code)]
use std::ops::Not; use std::ops::{
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
};
pub mod bigint; pub mod bigint;
pub mod rational; pub mod rational;
pub mod seq; pub mod seq;
/// Dummy trait for implementing generics on unsigned number types /// A Trait representing unsigned integer primitives
pub trait Unsigned: PartialEq + PartialOrd {} pub trait Unsigned:
Add
+ AddAssign
+ BitAnd
+ BitAndAssign
+ BitOr
+ BitOrAssign
+ BitXor
+ BitXorAssign
+ Div
+ DivAssign
+ Mul
+ MulAssign
+ Rem
+ RemAssign
+ Copy
+ Shl
+ ShlAssign
+ Shr
+ ShrAssign
+ Sub
+ SubAssign
+ Eq
+ Ord
+ Not
{
/// Find the greatest common denominator of two numbers
fn gcd(a: Self, b: Self) -> Self;
impl Unsigned for u8 {} /// Find the least common multiple of two numbers
impl Unsigned for u16 {} fn lcm(a: Self, b: Self) -> Self;
impl Unsigned for u32 {}
impl Unsigned for u64 {}
impl Unsigned for usize {}
impl Unsigned for u128 {}
#[derive(Debug, Copy, Clone)] /// The maximum value of the type
fn max_value() -> Self;
/// Is this a zero value?
fn is_zero(self) -> bool;
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Sign { pub enum Sign {
Positive, Positive,
Negative Negative,
}
impl Default for Sign {
fn default() -> Self {
Sign::Positive
}
} }
impl Not for Sign { impl Not for Sign {
@ -29,15 +68,79 @@ impl Not for Sign {
match self { match self {
Self::Positive => Self::Negative, Self::Positive => Self::Negative,
Self::Negative => Self::Positive, Self::Negative => Self::Positive,
_ => unreachable!()
} }
} }
} }
macro_rules! impl_unsigned {
($Type: ty) => {
impl Unsigned for $Type {
fn gcd(a: $Type, b: $Type) -> $Type {
if a == b {
return a;
} else if a == 0 {
return b;
} else if b == 0 {
return a;
}
let a_even = a % 2 == 0;
let b_even = b % 2 == 0;
if a_even {
if b_even {
// Both a & b are even
return Self::gcd(a >> 1, b >> 1) << 1;
} else if !b_even {
// b is odd
return Self::gcd(a >> 1, b);
}
}
// a is odd, b is even
if (!a_even) && b_even {
return Self::gcd(a, b >> 1);
}
if a > b {
return Self::gcd((a - b) >> 1, b);
}
Self::gcd((b - a) >> 1, a)
}
fn lcm(a: $Type, b: $Type) -> $Type {
if (a == 0 && b == 0) {
return 0;
}
a * b / Self::gcd(a, b)
}
fn max_value() -> $Type {
<$Type>::max_value()
}
fn is_zero(self) -> bool {
self == 0
}
}
};
}
impl_unsigned!(u8);
impl_unsigned!(u16);
impl_unsigned!(u32);
impl_unsigned!(u64);
impl_unsigned!(u128);
impl_unsigned!(usize);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
#[test] #[test]
fn it_works() { fn test_gcd() {
assert_eq!(2 + 2, 4); assert_eq!(u8::gcd(2, 2), 2);
assert_eq!(u16::gcd(36, 48), 12);
} }
} }

View File

@ -12,15 +12,9 @@
//! * SubAssign //! * SubAssign
use crate::{Sign, Unsigned}; use crate::{Sign, Unsigned};
use std::ops::Neg; use std::ops::{Mul, Neg};
#[derive(Debug, Copy, Clone)] #[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
pub enum FracType<T: Unsigned = usize> {
Proper(T, Frac),
Improper(Frac),
}
#[derive(Debug, Copy, Clone)]
pub struct Frac<T: Unsigned = usize> { pub struct Frac<T: Unsigned = usize> {
numer: T, numer: T,
denom: T, denom: T,
@ -30,14 +24,59 @@ pub struct Frac<T: Unsigned = usize> {
impl<T: Unsigned> Frac<T> { impl<T: Unsigned> Frac<T> {
/// Create a new rational number /// Create a new rational number
pub fn new(n: T, d: T) -> Self { pub fn new(n: T, d: T) -> Self {
if d.is_zero() {
panic!("Fraction can not have a zero denominator");
}
Frac { Frac {
numer: n, numer: n,
denom: d, denom: d,
sign: Sign::Positive, sign: Sign::Positive,
} }
.reduce()
}
pub fn new_neg(n: T, d: T) -> Self {
let mut frac = Frac::new(n, d);
frac.sign = Sign::Negative;
frac
}
fn reduce(mut self) -> Self {
let gcd = T::gcd(self.numer, self.denom);
self.numer /= gcd;
self.denom /= gcd;
self
} }
} }
macro_rules! impl_mul {
($Type: ty) => {
impl Mul for Frac<$Type> {
type Output = Self;
fn mul(self, rhs: Self) -> Self {
let numer = self.numer * rhs.numer;
let denom = self.denom * rhs.denom;
// Figure out the sign
if self.sign != rhs.sign {
Self::new_neg(numer, denom)
} else {
Self::new(numer, denom)
}
}
}
};
}
impl_mul!(u8);
impl_mul!(u16);
impl_mul!(u32);
impl_mul!(u64);
impl_mul!(usize);
impl<T: Unsigned> Neg for Frac<T> { impl<T: Unsigned> Neg for Frac<T> {
type Output = Self; type Output = Self;
@ -50,6 +89,4 @@ impl<T: Unsigned> Neg for Frac<T> {
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {}
}

View File

@ -1,11 +1,23 @@
///! Sequences and other 'stock' math functions //! Sequences and other 'stock' math functions
///! Calculate a number in the fibonacci sequence, /// Calculate a number in the fibonacci sequence,
///! using a lookup table for better worst-case performance. /// using a lookup table for better worst-case performance.
/// ///
/// Can calculate up to 186 using native unsigned 128 bit integers. /// Can calculate up to 186 using native unsigned 128 bit integers.
///
/// Example
/// ```rust
/// use rusty_numbers::seq::fibonacci;
///
/// let valid = fibonacci(45); // Some(1134903170)
/// # assert_eq!(1134903170, fibonacci(45).unwrap());
/// # assert!(valid.is_some());
///
/// let invalid = fibonacci(187); // None
/// # assert!(invalid.is_none());
/// ```
pub fn fibonacci(n: usize) -> Option<u128> { pub fn fibonacci(n: usize) -> Option<u128> {
let mut table: Vec<u128> = vec![]; let mut table: Vec<u128> = vec![0, 1, 1, 2, 3, 5];
_fibonacci(n, &mut table) _fibonacci(n, &mut table)
} }
@ -31,13 +43,12 @@ fn _fibonacci(n: usize, table: &mut Vec<u128>) -> Option<u128> {
} }
} }
///! Calculate the value of a factorial, /// Calculate the value of a factorial,
///! using a lookup table for better worst-case performance. /// using a lookup table for better worst-case performance.
/// ///
/// Can calculate up to 34! using native unsigned 128 bit integers. /// Can calculate up to 34! using native unsigned 128 bit integers.
/// If the result overflows, an error message will be displayed.
pub fn factorial(n: usize) -> Option<u128> { pub fn factorial(n: usize) -> Option<u128> {
let mut table: Vec<u128> = vec![0, 1, 1, 2, 3, 5]; let mut table: Vec<u128> = vec![1, 1, 2];
_factorial(n, &mut table) _factorial(n, &mut table)
} }
@ -75,6 +86,10 @@ mod tests {
#[test] #[test]
fn test_factorial() { fn test_factorial() {
assert_eq!(1, factorial(0).unwrap());
assert_eq!(1, factorial(1).unwrap());
assert_eq!(6, factorial(3).unwrap());
let res = factorial(34); let res = factorial(34);
assert!(res.is_some()); assert!(res.is_some());
@ -84,6 +99,10 @@ mod tests {
#[test] #[test]
fn test_fibonacci() { fn test_fibonacci() {
assert_eq!(0, fibonacci(0).unwrap());
assert_eq!(1, fibonacci(1).unwrap());
assert_eq!(1, fibonacci(2).unwrap());
let res = fibonacci(186); let res = fibonacci(186);
assert!(res.is_some()); assert!(res.is_some());