Move number traits into their own module
This commit is contained in:
parent
23d0ab75ec
commit
2e47d97cc7
@ -12,7 +12,7 @@
|
||||
//! * RemAssign
|
||||
//! * Sub
|
||||
//! * SubAssign
|
||||
use crate::{Sign, Unsigned};
|
||||
use crate::num::*;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BigInt {
|
||||
|
145
src/lib.rs
145
src/lib.rs
@ -1,146 +1,9 @@
|
||||
//! # Rusty Numbers
|
||||
//!
|
||||
//! Playin' with Numerics in Rust
|
||||
#![forbid(unsafe_code)]
|
||||
|
||||
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 num;
|
||||
pub mod rational;
|
||||
pub mod seq;
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Find the least common multiple of two numbers
|
||||
fn lcm(a: Self, b: Self) -> Self;
|
||||
|
||||
/// 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,
|
||||
}
|
||||
|
||||
impl Default for Sign {
|
||||
fn default() -> Self {
|
||||
Sign::Positive
|
||||
}
|
||||
}
|
||||
|
||||
impl Not for Sign {
|
||||
type Output = Sign;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
match self {
|
||||
Self::Positive => Self::Negative,
|
||||
Self::Negative => Self::Positive,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 test_gcd() {
|
||||
assert_eq!(u8::gcd(2, 2), 2);
|
||||
assert_eq!(u16::gcd(36, 48), 12);
|
||||
}
|
||||
}
|
||||
|
159
src/num.rs
Normal file
159
src/num.rs
Normal file
@ -0,0 +1,159 @@
|
||||
//! Numeric Helper Traits
|
||||
use std::ops::{
|
||||
Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign,
|
||||
Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign,
|
||||
};
|
||||
|
||||
/// Native number type
|
||||
pub trait Num:
|
||||
Add + AddAssign + Div + DivAssign + Mul + MulAssign + Rem + RemAssign + Copy + Sub + SubAssign
|
||||
{
|
||||
}
|
||||
|
||||
/// Integer primitive
|
||||
pub trait Int:
|
||||
Num
|
||||
+ BitAnd
|
||||
+ BitAndAssign
|
||||
+ BitOr
|
||||
+ BitOrAssign
|
||||
+ BitXor
|
||||
+ BitXorAssign
|
||||
+ Eq
|
||||
+ Ord
|
||||
+ Not
|
||||
+ Shl
|
||||
+ Shr
|
||||
+ ShlAssign
|
||||
+ ShrAssign
|
||||
{
|
||||
/// The maximum value of the type
|
||||
fn max_value() -> Self;
|
||||
|
||||
/// Is this a zero value?
|
||||
fn is_zero(self) -> bool;
|
||||
}
|
||||
|
||||
/// A Trait representing unsigned integer primitives
|
||||
pub trait Unsigned: Int {
|
||||
/// Find the greatest common denominator of two numbers
|
||||
fn gcd(a: Self, b: Self) -> Self;
|
||||
|
||||
/// Find the least common multiple of two numbers
|
||||
fn lcm(a: Self, b: Self) -> Self;
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum Sign {
|
||||
Positive,
|
||||
Negative,
|
||||
}
|
||||
|
||||
impl Default for Sign {
|
||||
fn default() -> Self {
|
||||
Sign::Positive
|
||||
}
|
||||
}
|
||||
|
||||
impl Not for Sign {
|
||||
type Output = Sign;
|
||||
|
||||
fn not(self) -> Self::Output {
|
||||
match self {
|
||||
Self::Positive => Self::Negative,
|
||||
Self::Negative => Self::Positive,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_num {
|
||||
($( $Type: ty ),* ) => {
|
||||
$(
|
||||
impl Num for $Type {
|
||||
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_int {
|
||||
($( $Type: ty ),* ) => {
|
||||
$(
|
||||
impl Int for $Type {
|
||||
fn is_zero(self) -> bool {
|
||||
self == 0
|
||||
}
|
||||
|
||||
fn max_value() -> $Type {
|
||||
<$Type>::max_value()
|
||||
}
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_unsigned {
|
||||
($($Type: ty),* ) => {
|
||||
$(
|
||||
impl Unsigned for $Type {
|
||||
/// Implementation based on https://en.wikipedia.org/wiki/Binary_GCD_algorithm
|
||||
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)
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_num!(i8, u8, i16, u16, f32, i32, u32, f64, i64, u64, i128, u128, usize);
|
||||
impl_int!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, usize);
|
||||
impl_unsigned!(u8, u16, u32, u64, u128, usize);
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_gcd() {
|
||||
assert_eq!(u8::gcd(2, 2), 2);
|
||||
assert_eq!(u16::gcd(36, 48), 12);
|
||||
}
|
||||
}
|
@ -11,7 +11,7 @@
|
||||
//! * Sub
|
||||
//! * SubAssign
|
||||
|
||||
use crate::{Sign, Unsigned};
|
||||
use crate::num::*;
|
||||
use std::ops::{Mul, Neg};
|
||||
|
||||
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
|
||||
|
Loading…
Reference in New Issue
Block a user