From aae00e2031cfa992d0c505c095a2136eb469d583 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Fri, 14 Feb 2020 23:41:14 -0500 Subject: [PATCH] Sort of get fractions to work from signed or unsigned numbers --- src/num.rs | 85 ++++++++++++++++++++++++++++++++++++-------- src/rational.rs | 94 +++++++++++++++++-------------------------------- 2 files changed, 103 insertions(+), 76 deletions(-) diff --git a/src/num.rs b/src/num.rs index f39326c..6a9ba7c 100644 --- a/src/num.rs +++ b/src/num.rs @@ -1,14 +1,38 @@ //! Numeric Helper Traits -use std::convert::TryFrom; -use std::ops::{ +#![allow(unused_comparisons)] +use core::convert::TryFrom; +use core::fmt::Debug; +use core::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 + Add + + AddAssign + + Debug + + Div + + DivAssign + + Mul + + MulAssign + + Rem + + RemAssign + + PartialOrd + + PartialEq + + Copy + + Sub + + SubAssign { + /// Is this number type signed? + fn is_signed(&self) -> bool { + true + } +} + +/// Float primitive +pub trait Float: Num { + fn is_neg(self) -> bool; } /// Integer primitive @@ -33,6 +57,9 @@ pub trait Int: /// Is this a zero value? fn is_zero(self) -> bool; + + /// Is this number less than zero? + fn is_neg(self) -> bool; } /// A Trait representing unsigned integer primitives @@ -43,14 +70,16 @@ pub trait Unsigned: Int { /// Find the least common multiple of two numbers fn lcm(a: Self, b: Self) -> Self; - fn is_signed(self) -> bool; + fn is_signed(self) -> bool { + false + } } /// A Trait representing signed integer primitives -pub trait Signed: Int { - fn is_neg(self) -> bool; +pub trait Signed: Int { + type Un; - fn to_unsigned(self) -> U; + fn to_unsigned(self) -> Self::Un; } #[derive(Debug, Copy, Clone, PartialEq, Eq)] @@ -86,6 +115,18 @@ macro_rules! impl_num { } } +macro_rules! impl_float { + ($( $Type: ty ),* ) => { + $( + impl Float for $Type { + fn is_neg(self) -> bool { + self < 0.0 + } + } + )* + } +} + macro_rules! impl_int { ($( $Type: ty ),* ) => { $( @@ -97,6 +138,16 @@ macro_rules! impl_int { fn max_value() -> $Type { <$Type>::max_value() } + + /// Is this number less than zero? + + fn is_neg(self) -> bool { + if self.is_signed() == false { + false + } else { + self < 0 + } + } } )* } @@ -156,16 +207,14 @@ macro_rules! impl_unsigned { macro_rules! impl_signed { ($(($type: ty, $un_type: ty)),* ) => { $( - impl Signed for $type { - fn is_neg(self) -> bool { - self < 0 - } + impl Signed for $type { + type Un = $un_type; - fn to_unsigned(self) -> U { + fn to_unsigned(self) -> $un_type { // Converting from signed to unsigned should always be safe // when using the absolute value, especially since I'm converting // between the same bit size - ::try_from(self).unwrap() + <$un_type>::try_from(self).unwrap() } } )* @@ -173,9 +222,17 @@ macro_rules! impl_signed { } impl_num!(i8, u8, i16, u16, f32, i32, u32, f64, i64, u64, i128, u128, isize, usize); +impl_float!(f32, f64); impl_int!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize); impl_unsigned!(u8, u16, u32, u64, u128, usize); -impl_signed!((i8,u8),(i16,u16),(i32,u32),(i64,u64),(i128,u128),(isize,usize)); +impl_signed!( + (i8, u8), + (i16, u16), + (i32, u32), + (i64, u64), + (i128, u128), + (isize, usize) +); #[cfg(test)] mod tests { diff --git a/src/rational.rs b/src/rational.rs index ee49d97..1000804 100644 --- a/src/rational.rs +++ b/src/rational.rs @@ -24,66 +24,36 @@ pub struct Frac { #[macro_export] macro_rules! frac { ($n:literal / $d:literal) => { - Frac::new_conv($n, $d) + frac($n, $d) + }; + ($n:literal / $d:literal) => { + frac($n, $d) }; } -/* macro_rules! impl_from_signed { - ($(($in_type: ty, $out_type: ty)),* ) => { - $( - impl Frac<$in_type> { - pub fn new(n: $in_type, d: $in_type) -> Frac<$out_type> { - // Converting from signed to unsigned should always be safe - // when using the absolute value, especially since I'm converting - // between the same bit size - let mut sign = $crate::num::Sign::Positive; - let numer = <$out_type>::try_from(n.abs()).unwrap(); - let denom = <$out_type>::try_from(d.abs()).unwrap(); +/// Create a new rational number +pub fn frac, U: Unsigned>(n: S, d: S) -> Frac { + // Converting from signed to unsigned should always be safe + // when using the absolute value, especially since I'm converting + // between the same bit size + let mut sign = Sign::Positive; + let numer = n.to_unsigned(); + let denom = d.to_unsigned(); - if n < 0 { - sign = !sign; - } - - if d < 0 { - sign = !sign; - } - - Frac::new_signed(numer, denom, sign) - } - - fn new_signed(n: $in_type, d: $in_type, _: $crate::num::Sign) -> Frac<$out_type> { - Self::new(n, d) - } - } - )* - }; -} -impl_from_signed!((i8, u8), (i16, u16), (i32, u32), (i64, u64), (i128, u128), (isize, usize)); */ - -impl Frac { - pub fn new_conv(n: T, d: T) -> Self { - // Converting from signed to unsigned should always be safe - // when using the absolute value, especially since I'm converting - // between the same bit size - let mut sign = Sign::Positive; - let numer:T::Un = n.to_unsigned(); - let denom:T::Un = d.to_unsigned(); - - if n.is_neg() { - sign = !sign; - } - - if d.is_neg() { - sign = !sign; - } - - Self::new(numer, denom, sign) + if n.is_neg() { + sign = !sign; } + + if d.is_neg() { + sign = !sign; + } + + Frac { numer, denom, sign }.reduce() } impl Frac { /// Create a new rational number - pub fn new(n: T, d: T, s: Sign) -> Self { + pub fn new(n: T, d: T, s: Sign) -> Frac { if d.is_zero() { panic!("Fraction can not have a zero denominator"); } @@ -123,7 +93,7 @@ impl> Mul for Frac { let denom = self.denom * rhs.denom; let sign = Self::get_sign(self, rhs); - Self::new_signed(numer, denom, sign) + Self::new(numer, denom, sign) } } @@ -135,7 +105,7 @@ impl> Div for Frac { let denom = self.denom * rhs.numer; let sign = Self::get_sign(self, rhs); - Self::new_signed(numer, denom, sign) + Self::new(numer, denom, sign) } } @@ -150,9 +120,9 @@ impl + Sub + Mul> Add for // subtraction is equivalent if self.sign != rhs.sign { if a.numer > b.numer { - return a - b + return a - b; } else if a.numer < b.numer { - return b - a + return b - a; } } @@ -164,14 +134,14 @@ impl + Sub + Mul> Add for let denom = a.denom * b.denom; let sign = Self::get_sign(a, b); - return Self::new_signed(numer, denom, sign); + return Self::new(numer, denom, sign); } let numer = a.numer + b.numer; let denom = self.denom; let sign = Self::get_sign(a, b); - Self::new_signed(numer, denom, sign) + Self::new(numer, denom, sign) } } @@ -213,17 +183,17 @@ mod tests { #[test] fn add_test() { - assert_eq!(frac!(5u8 / 6), frac!(1 / 3) + frac!(1 / 2)); + assert_eq!(frac!(5 / 6), frac!(1 / 3) + frac!(1 / 2)); } #[test] fn macro_test() { - let frac1 = frac!(1u8 / 3); - let frac2 = Frac::new(1u8, 3, Sign::Positive); + let frac1 = frac!(1 / 3); + let frac2 = Frac::new(1u32, 3, Sign::Positive); assert_eq!(frac1, frac2); - let frac1 = -frac!(1u8 / 2); - let frac2 = Frac::new(1u8, 2, Sign::Negative); + let frac1 = -frac!(1 / 2); + let frac2 = Frac::new(1u32, 2, Sign::Negative); assert_eq!(frac1, frac2); } }