//! # Rational Numbers (fractions) //! //! Traits to implement: //! * Add //! * AddAssign //! * Div //! * DivAssign //! * Mul //! * MulAssign //! * Neg //! * Sub //! * SubAssign use crate::{Sign, Unsigned}; use std::ops::{Mul, Neg}; #[derive(Debug, Default, Copy, Clone, Eq, PartialEq)] pub struct Frac { numer: T, denom: T, sign: Sign, } impl Frac { /// 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 Neg for Frac { type Output = Self; fn neg(self) -> Self::Output { let mut out = self.clone(); out.sign = !self.sign; out } } #[cfg(test)] mod tests {}