#![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 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); } }