Pass cargo check and tests
This commit is contained in:
parent
421d548082
commit
23d0ab75ec
@ -34,7 +34,7 @@ impl<T: Unsigned> From<T> for BigInt {
|
||||
let mut new = Self::default();
|
||||
|
||||
if n > T::max_value() {
|
||||
new.inner = BigInt::split(n);
|
||||
new.split(n);
|
||||
}
|
||||
|
||||
new
|
||||
@ -42,24 +42,21 @@ impl<T: Unsigned> From<T> for BigInt {
|
||||
}
|
||||
|
||||
impl BigInt {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
/// 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!
|
||||
if num < T::max_value() {
|
||||
return vec![T::into()];
|
||||
todo!();
|
||||
// return vec![num as usize];
|
||||
}
|
||||
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
|
||||
impl BigInt {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
}
|
||||
mod tests {}
|
||||
|
131
src/lib.rs
131
src/lib.rs
@ -1,25 +1,64 @@
|
||||
#![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 rational;
|
||||
pub mod seq;
|
||||
|
||||
/// Dummy trait for implementing generics on unsigned number types
|
||||
pub trait Unsigned: PartialEq + PartialOrd {}
|
||||
/// A Trait representing unsigned integer primitives
|
||||
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 {}
|
||||
impl Unsigned for u16 {}
|
||||
impl Unsigned for u32 {}
|
||||
impl Unsigned for u64 {}
|
||||
impl Unsigned for usize {}
|
||||
impl Unsigned for u128 {}
|
||||
/// Find the least common multiple of two numbers
|
||||
fn lcm(a: Self, b: Self) -> Self;
|
||||
|
||||
#[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 {
|
||||
Positive,
|
||||
Negative
|
||||
Negative,
|
||||
}
|
||||
|
||||
impl Default for Sign {
|
||||
fn default() -> Self {
|
||||
Sign::Positive
|
||||
}
|
||||
}
|
||||
|
||||
impl Not for Sign {
|
||||
@ -29,15 +68,79 @@ impl Not for Sign {
|
||||
match self {
|
||||
Self::Positive => Self::Negative,
|
||||
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)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(2 + 2, 4);
|
||||
fn test_gcd() {
|
||||
assert_eq!(u8::gcd(2, 2), 2);
|
||||
assert_eq!(u16::gcd(36, 48), 12);
|
||||
}
|
||||
}
|
||||
|
@ -12,15 +12,9 @@
|
||||
//! * SubAssign
|
||||
|
||||
use crate::{Sign, Unsigned};
|
||||
use std::ops::Neg;
|
||||
use std::ops::{Mul, Neg};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum FracType<T: Unsigned = usize> {
|
||||
Proper(T, Frac),
|
||||
Improper(Frac),
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct Frac<T: Unsigned = usize> {
|
||||
numer: T,
|
||||
denom: T,
|
||||
@ -30,14 +24,59 @@ pub struct Frac<T: Unsigned = usize> {
|
||||
impl<T: Unsigned> Frac<T> {
|
||||
/// Create a new rational number
|
||||
pub fn new(n: T, d: T) -> Self {
|
||||
if d.is_zero() {
|
||||
panic!("Fraction can not have a zero denominator");
|
||||
}
|
||||
|
||||
Frac {
|
||||
numer: n,
|
||||
denom: d,
|
||||
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> {
|
||||
type Output = Self;
|
||||
|
||||
@ -50,6 +89,4 @@ impl<T: Unsigned> Neg for Frac<T> {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
}
|
||||
mod tests {}
|
||||
|
37
src/seq.rs
37
src/seq.rs
@ -1,11 +1,23 @@
|
||||
///! Sequences and other 'stock' math functions
|
||||
//! Sequences and other 'stock' math functions
|
||||
|
||||
///! Calculate a number in the fibonacci sequence,
|
||||
///! using a lookup table for better worst-case performance.
|
||||
/// Calculate a number in the fibonacci sequence,
|
||||
/// using a lookup table for better worst-case performance.
|
||||
///
|
||||
/// 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> {
|
||||
let mut table: Vec<u128> = vec![];
|
||||
let mut table: Vec<u128> = vec![0, 1, 1, 2, 3, 5];
|
||||
|
||||
_fibonacci(n, &mut table)
|
||||
}
|
||||
@ -31,20 +43,19 @@ fn _fibonacci(n: usize, table: &mut Vec<u128>) -> Option<u128> {
|
||||
}
|
||||
}
|
||||
|
||||
///! Calculate the value of a factorial,
|
||||
///! using a lookup table for better worst-case performance.
|
||||
/// Calculate the value of a factorial,
|
||||
/// using a lookup table for better worst-case performance.
|
||||
///
|
||||
/// 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> {
|
||||
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)
|
||||
}
|
||||
|
||||
/// Actual Calculation function for factoral
|
||||
#[inline]
|
||||
fn _factorial (n: usize, table: &mut Vec<u128>) -> Option<u128> {
|
||||
fn _factorial(n: usize, table: &mut Vec<u128>) -> Option<u128> {
|
||||
match table.get(n) {
|
||||
// Vec<T>.get returns a Option with a reference to the value,
|
||||
// so deref and wrap in Some() for proper return type
|
||||
@ -75,6 +86,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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);
|
||||
assert!(res.is_some());
|
||||
|
||||
@ -84,6 +99,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
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);
|
||||
assert!(res.is_some());
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user