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();
|
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 {}
|
||||||
|
|
||||||
}
|
|
||||||
|
131
src/lib.rs
131
src/lib.rs
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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 {}
|
||||||
|
|
||||||
}
|
|
||||||
|
35
src/seq.rs
35
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,
|
/// 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());
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user