use num_traits::sign::Signed; use num_traits::Num; use num_traits::NumOps; use num_traits::One; use num_traits::Pow; use num_traits::Signed as SignedOps; use num_traits::Zero; use std::cmp::Ordering; use std::cmp::PartialEq; use std::cmp::PartialOrd; use std::fmt::Debug; use std::fmt::Display; use std::ops::Add; use std::ops::AddAssign; use std::ops::Div; use std::ops::DivAssign; use std::ops::Mul; use std::ops::MulAssign; use std::ops::Neg; use std::ops::Rem; use std::ops::Sub; use std::ops::SubAssign; trait_group! { pub trait RationalInt : NumOps + Debug + PartialEq + PartialOrd + Zero + One + Pow + Neg + Clone + Default } fn gcd(a: &T, b: &T) -> T where T: Rem + Clone + Zero, { let mut n1 = a.clone(); let mut n2 = b.clone(); let mut tmp: T; while !n2.is_zero() { tmp = n1; n1 = n2.clone(); n2 = tmp % n2; } n1 } fn mcm<'a, T>(n1: &'a T, n2: &'a T) -> T where T: Div + Rem + Clone + Zero, &'a T: Mul, { let den = gcd(n1, n2); n1 * n2 / den } #[derive(Debug)] pub struct Rational { num: TYPE, den: TYPE, } impl Rational where TYPE: Zero + One + Clone + Rem + PartialOrd + Neg, for<'a> &'a TYPE: Div<&'a TYPE, Output = TYPE>, { fn simplify(&mut self) { if self.num.is_zero() { self.den = TYPE::one(); } else if self.den.is_zero() { } else { (self.num, self.den) = { let n1_opt: TYPE; let n1 = if self.den < TYPE::zero() { n1_opt = -self.num.clone(); &n1_opt } else { &self.num }; let n2_opt: TYPE; let n2 = if self.den < TYPE::zero() { n2_opt = -self.den.clone(); &n2_opt } else { &self.den }; let num_abs_opt: TYPE; let num_abs = if self.num < TYPE::zero() { num_abs_opt = -self.num.clone(); &num_abs_opt } else { &self.num }; let gcd = gcd(num_abs, n2); (n1 / &gcd, n2 / &gcd) }; } } } impl Rational where TYPE: RationalInt, { pub fn new(num: TYPE, den: TYPE) -> Rational { let res = den.partial_cmp(&TYPE::zero()); match res { Some(Ordering::Greater) => Rational { num, den }, Some(Ordering::Less) => Rational { num: -num, den: -den, }, _ => { panic!("Rational denominator cannot be zero or NaN") } } } } #[opimps::impl_op(Pow)] fn pow(self: Rational, exp: u32) -> Rational where TYPE: RationalInt, for<'a> &'a TYPE: Pow, { Rational { num: self.num.pow(exp), den: self.den.pow(exp), } } #[opimps::impl_op(Pow)] fn pow(self: &Rational, exp: u32) -> Rational where TYPE: RationalInt, for<'a> &'a TYPE: Pow, { Rational { num: (&self.num).pow(exp), den: (&self.den).pow(exp), } } #[opimps::impl_ops(Add)] fn add(self: Rational, rhs: Rational) -> Rational where TYPE: RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { let den = mcm::(&self.den, &rhs.den); let a = &self.num * &den; let b = &rhs.num * &den; let num = &a / &self.den + &b / &rhs.den; let mut result: Rational = Rational { num, den }; result.simplify(); result } #[opimps::impl_ops(Sub)] fn sub(self: Rational, rhs: Rational) -> Rational where TYPE: RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { let den = mcm::(&self.den, &rhs.den); let a = &self.num * &den; let b = &rhs.num * &den; let num = &a / &self.den - &b / &rhs.den; let mut result: Rational = Rational { num, den }; result.simplify(); result } #[opimps::impl_ops(Mul)] fn mul(self: Rational, rhs: Rational) -> Rational where TYPE: RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { let num = &self.num * &rhs.num; let den = &self.den * &rhs.den; let mut result = Rational { num, den }; result.simplify(); result } #[opimps::impl_ops(Div)] fn div(self: Rational, rhs: Rational) -> Rational where TYPE: RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { let den = &self.den * &rhs.num; let num = &self.num * &rhs.den; let mut result = Rational::new(num, den); result.simplify(); result } #[opimps::impl_ops(Rem)] fn rem(self: Rational, rhs: Rational) -> Rational where TYPE: RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { match self.partial_cmp(&rhs) { Some(std::cmp::Ordering::Less) => rhs.clone(), Some(std::cmp::Ordering::Equal) => Rational::::zero(), Some(std::cmp::Ordering::Greater) => { let div = self / rhs; let num = &div.num / &div.den; div - Rational::new(num, TYPE::one()) } None => { panic!("Cannot compare") } } } impl<'a, TYPE> AddAssign<&'a Rational> for Rational where TYPE: Zero + One + Clone + Rem + PartialOrd + Neg + Div, for<'b> &'b TYPE: Mul<&'b TYPE, Output = TYPE> + Div<&'b TYPE, Output = TYPE>, { fn add_assign(&mut self, rhs: &'a Self) { let den = mcm::(&self.den, &rhs.den); let a = &self.num * &den; let b = &rhs.num * &den; let num = &a / &self.den + &b / &rhs.den; self.num = num; self.den = den; self.simplify(); } } impl AddAssign for Rational where TYPE: RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { fn add_assign(&mut self, rhs: Self) { *self += &rhs; } } impl<'a, TYPE> SubAssign<&'a Rational> for Rational where TYPE: Div + Sub + Rem + Neg + Clone + Zero + One + PartialOrd, for<'c> &'c TYPE: Mul<&'c TYPE, Output = TYPE> + Div<&'c TYPE, Output = TYPE>, for<'b> TYPE: SubAssign<&'b TYPE>, { fn sub_assign(&mut self, rhs: &'a Self) { let den = mcm::(&self.den, &rhs.den); let a = &self.num * &den; let b = &rhs.num * &den; let num = &a / &self.den - &b / &rhs.den; self.num = num; self.den = den; self.simplify(); } } impl SubAssign for Rational where TYPE: Div + Sub + Rem + Neg + Clone + Zero + One + PartialOrd, for<'c> &'c TYPE: Mul<&'c TYPE, Output = TYPE> + Div<&'c TYPE, Output = TYPE>, for<'b> TYPE: SubAssign<&'b TYPE>, { fn sub_assign(&mut self, rhs: Self) { *self -= &rhs; } } impl<'a, TYPE> MulAssign<&'a Rational> for Rational where for<'b> TYPE: MulAssign<&'b TYPE>, TYPE: PartialOrd + One + Clone + Zero + Rem + Neg, for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>, { fn mul_assign(&mut self, rhs: &'a Self) { self.num *= &rhs.num; self.den *= &rhs.den; self.simplify(); } } impl MulAssign for Rational where for<'a> TYPE: MulAssign<&'a TYPE>, TYPE: PartialOrd + One + Clone + Zero + Rem + Neg, for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>, { fn mul_assign(&mut self, rhs: Self) { *self *= &rhs; } } impl<'a, TYPE> DivAssign<&'a Rational> for Rational where for<'b> TYPE: MulAssign<&'b TYPE>, TYPE: PartialOrd + One + Clone + Zero + Rem + Neg, for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>, { fn div_assign(&mut self, rhs: &'a Self) { self.num *= &rhs.den; self.den *= &rhs.num; self.simplify() } } impl DivAssign for Rational where for<'a> TYPE: MulAssign<&'a TYPE>, TYPE: PartialOrd + One + Clone + Zero + Rem + Neg, for<'c> &'c TYPE: Div<&'c TYPE, Output = TYPE>, { fn div_assign(&mut self, rhs: Self) { *self /= &rhs; self.simplify() } } impl Display for Rational where TYPE: RationalInt + Display, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}/{}", self.num, self.den) } } impl PartialEq for Rational where TYPE: RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { fn eq(&self, other: &Self) -> bool { self.partial_cmp(other) == Some(Ordering::Equal) } } impl Eq for Rational where TYPE: RationalInt + Eq, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { } impl PartialOrd for Rational where TYPE: RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { fn partial_cmp(&self, other: &Self) -> Option { (&self.num * &other.den).partial_cmp(&(&other.num * &self.den)) } } impl Ord for Rational where TYPE: RationalInt + Ord, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { fn cmp(&self, other: &Self) -> Ordering { (&self.num * &other.den).cmp(&(&other.num * &self.den)) } } impl Clone for Rational where TYPE: Clone, { fn clone(&self) -> Self { Rational { num: self.num.clone(), den: self.den.clone(), } } } impl Copy for Rational where TYPE: Copy {} impl Zero for Rational where TYPE: RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { fn zero() -> Rational { Rational { num: TYPE::zero(), den: TYPE::one(), } } fn is_zero(&self) -> bool { self.num.is_zero() && !self.den.is_zero() } } impl One for Rational where TYPE: RationalInt + Display, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { fn one() -> Self { Rational { num: TYPE::one(), den: TYPE::one(), } } fn is_one(&self) -> bool { self.num == self.den } } impl Default for Rational where TYPE: RationalInt + Display, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { fn default() -> Self { Rational::::zero() } } #[opimps::impl_uni_op(Neg)] fn neg(self: Rational) -> Rational where TYPE: RationalInt, { Rational::new(-self.num, self.den) } #[opimps::impl_uni_op(Neg)] fn neg(self: &Rational) -> Rational where TYPE: RationalInt, { Rational::new(-self.num.clone(), self.den.clone()) } impl Num for Rational where TYPE: Num + RationalInt + Display, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { fn from_str_radix(_: &str, _: u32) -> Result { Result::Err(Rational::::default()) } type FromStrRadixErr = Self; } impl SignedOps for Rational where TYPE: Signed + SignedOps + Display + RationalInt, for<'a> &'a TYPE: NumOps<&'a TYPE, TYPE>, { fn abs(&self) -> Self { Rational::new(self.num.abs(), self.den.abs()) } fn abs_sub(&self, other: &Self) -> Self { if self <= other { Rational::::zero() } else { self.clone() - other.clone() } } fn is_negative(&self) -> bool { !self.num.is_zero() && self.num.is_negative() ^ self.den.is_negative() } fn is_positive(&self) -> bool { !self.num.is_zero() && !(self.num.is_positive() ^ self.den.is_positive()) } fn signum(&self) -> Self { if self.is_positive() { Rational::::one() } else if self.is_negative() { -Rational::::one() } else { Rational::::zero() } } } #[cfg(test)] mod tests { use super::*; use std::collections::BTreeSet; #[test] fn test_simplify() { let mut r1 = Rational::new(15, 105); assert_eq!(Rational::new(1, 7), r1); r1.simplify(); assert_eq!(Rational::new(1, 7), r1); } #[test] fn test_add() { let r1 = Rational::new(3, 5); let r2 = Rational::new(4, 10); let r3 = Rational::new(1, 7); let one: Rational = Rational::::one(); assert_eq!(one, r1 + r2); assert_eq!(r2 + r1, r1 + r2); assert_eq!(r1 + r2 + r3, r3 + r2 + r1); } #[test] fn test_add_assign() { let mut r1 = Rational::new(3, 5); let r2 = Rational::new(4, 10); let r3 = Rational::::one(); r1 += r2; assert_eq!(r3, r1); } #[test] fn test_sub() { let r1 = Rational::new(3, 5); let r2 = Rational::new(4, 10); let r3 = Rational::new(1, 7); assert_eq!(Rational::::zero(), r1 - r1); assert_eq!(Rational::new(-1, 5), r2 - r1); assert!(Rational::::zero() > r3 - r1); assert!(Rational::::zero() > r3 - r2); assert!(Rational::::zero() > r3 - r1); } #[test] fn test_sub_assign() { let mut r1 = Rational::new(3, 5); let r2 = Rational::new(4, 10); let r3 = Rational::new(1, 5); r1 -= r2; assert_eq!(r3, r1); } #[test] fn test_mul() { let r1 = Rational::new(3, 5); let r2 = Rational::new(-4, 10); let r3 = Rational::new(1, 7); assert_eq!(Rational::new(9, 25), r1 * r1); assert_eq!(Rational::new(-12, 50), r2 * r1); assert_eq!(Rational::new(2, -35), r2 * r3); } #[test] fn test_mul_assign() { let r1 = Rational::new(3, 5); let r2 = Rational::new(-4, 10); let r3 = Rational::new(-12, 50); let mut r4 = r1.clone(); r4 *= r1; assert_eq!(Rational::::new(9, 25), r4); let mut r5 = r1.clone(); r5 *= r2; assert_eq!(r3, r5); } #[test] fn test_div() { let r1 = Rational::new(3, 5); let r2 = Rational::new(-4, 10); let r3 = Rational::new(1, 7); assert_eq!(Rational::::one(), r1 / r1); assert_eq!(Rational::new(-2, 3), r2 / r1); assert_eq!(Rational::new(28, -10), r2 / r3); } #[test] fn test_div_assign() { let r1 = Rational::new(3, 5); let r2 = Rational::new(-4, 10); let r3 = Rational::new(30, -20); let mut r4 = r1.clone(); r4 /= r1; assert_eq!(Rational::::one(), r4); let mut r5 = r1.clone(); r5 /= r2; assert_eq!(r3, r5); } #[test] fn test_eq() { let r1 = Rational::new(3, 5); let r2 = Rational::new(6, 10); let r3 = Rational::new(300, 500); let r4 = Rational::new(300, -500); assert!(r1 == r2); assert!(r1 == r3); assert!(r1 != r4); } #[test] fn test_ord() { let r1 = Rational::new(3, 5); let r2 = Rational::new(7, 10); let r3 = Rational::new(301, 500); let r4 = Rational::new(300, -500); let values: Vec> = BTreeSet::from([r1, r2, r3, r4]) .iter() .map(|it| it.clone()) .collect(); let expected_order = Vec::from([r4, r1, r3, r2]); assert_eq!(expected_order, values); } #[test] fn test_gcd() { let a = 14; let b = 21; assert_eq!(7, gcd(&a, &b)); } #[test] fn test_mcm() { let a = 14; let b = 21; assert_eq!(42, mcm::(&a, &b)); } } #[cfg(test)] mod big_int_tests { use super::*; use num_bigint::BigInt; use std::collections::BTreeSet; #[test] fn test_gcd() { assert_eq!(6, gcd(&12, &18)); assert_eq!(6, gcd(&18, &12)); } #[test] fn test_simplify() { let mut r1 = Rational::new(BigInt::from(15), BigInt::from(105)); assert_eq!(Rational::new(BigInt::from(1), BigInt::from(7)), r1); r1.simplify(); assert_eq!(Rational::new(BigInt::from(1), BigInt::from(7)), r1); } #[test] fn test_add() { let r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(4), BigInt::from(10)); let r3 = Rational::new(BigInt::from(1), BigInt::from(7)); assert_eq!(Rational::::one(), &r1 + &r2); assert_eq!(&r2 + &r1, &r1 + &r2); assert_eq!(&r1 + &r2 + &r3, &r3 + &r2 + &r1); } #[test] fn test_add_assign() { let mut r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(4), BigInt::from(10)); r1 += r2; assert_eq!(Rational::::one(), r1); } #[test] fn test_sub() { let r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(4), BigInt::from(10)); let r3 = Rational::new(BigInt::from(1), BigInt::from(7)); assert_eq!(Rational::::zero(), &r1 - &r1); assert_eq!(Rational::new(BigInt::from(-1), BigInt::from(5)), &r2 - &r1); assert!(Rational::::zero() > &r3 - &r1); assert!(Rational::::zero() > &r3 - &r2); assert!(Rational::::zero() > r3 - r1); } #[test] fn test_sub_assign() { let mut r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(4), BigInt::from(10)); r1 -= r2; assert_eq!(Rational::::new(BigInt::one(), BigInt::from(5)), r1); } #[test] fn test_mul() { let r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(-4), BigInt::from(10)); let r3 = Rational::new(BigInt::from(1), BigInt::from(7)); assert_eq!(Rational::new(BigInt::from(9), BigInt::from(25)), &r1 * &r1); assert_eq!( Rational::new(BigInt::from(-12), BigInt::from(50)), &r2 * &r1 ); assert_eq!(Rational::new(BigInt::from(2), BigInt::from(-35)), r2 * r3); } #[test] fn test_mul_assign() { let r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(-4), BigInt::from(10)); let r3 = Rational::new(BigInt::from(-12), BigInt::from(50)); let mut r4 = r1.clone(); r4 *= &r1; assert_eq!( Rational::::new(BigInt::from(9), BigInt::from(25)), r4 ); let mut r5 = r1.clone(); r5 *= r2; assert_eq!(r3, r5); } #[test] fn test_div() { let r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(-4), BigInt::from(10)); let r3 = Rational::new(BigInt::from(1), BigInt::from(7)); assert_eq!(Rational::::one(), &r1 / &r1); assert_eq!(Rational::new(BigInt::from(-2), BigInt::from(3)), &r2 / r1); assert_eq!(Rational::new(BigInt::from(28), BigInt::from(-10)), r2 / r3); } #[test] fn test_div_assign() { let r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(-4), BigInt::from(10)); let r3 = Rational::new(BigInt::from(30), BigInt::from(-20)); let mut r4 = r1.clone(); r4 /= &r1; assert_eq!(Rational::::one(), r4); let mut r5 = r1.clone(); r5 /= r2; assert_eq!(r3, r5); } #[test] fn test_eq() { let r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(6), BigInt::from(10)); let r3 = Rational::new(BigInt::from(300), BigInt::from(500)); let r4 = Rational::new(BigInt::from(300), BigInt::from(-500)); assert!(r1 == r2); assert!(r1 == r3); assert!(r1 != r4); } #[test] fn test_ord() { let r1 = Rational::new(BigInt::from(3), BigInt::from(5)); let r2 = Rational::new(BigInt::from(7), BigInt::from(10)); let r3 = Rational::new(BigInt::from(301), BigInt::from(500)); let r4 = Rational::new(BigInt::from(300), BigInt::from(-500)); let values: Vec<&Rational> = BTreeSet::from([&r1, &r2, &r3, &r4]) .iter() .map(|it| *it) .collect(); let expected_order = Vec::from([&r4, &r1, &r3, &r2]); assert_eq!(expected_order, values); } }