use std::ops::*; use std::fmt::{Debug, Formatter, Error}; #[derive(Copy, Clone)] pub struct Rational { n: i64, d: i64 } fn gcd(a: i64, b: i64) -> i64 {match b { 0 => a, _ => gcd(b, a % b) }} impl Default for Rational { fn default() -> Rational { Rational::from_int(0) } } impl Debug for Rational { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { f.write_fmt(format_args!("{}/{}", self.n, self.d)) } } impl Add for Rational { type Output = Self; fn add(self, other: Self) -> Self { let c = gcd(self.d, other.d); Rational{n: self.n * (other.d / c) + other.n * (self.d / c), d: self.d / c * other.d}.reduced() } } impl AddAssign for Rational { fn add_assign(&mut self, other: Self) { let c = gcd(self.d, other.d); *self = Rational{n: self.n * (other.d / c) + other.n * (self.d / c), d: self.d / c * other.d}.reduced() } } impl Mul for Rational { type Output = Self; fn mul(self, other: Self) -> Self { Rational{n: self.n * other.n, d: self.d * other.d}.reduced() } } impl Div for Rational { type Output = Self; fn div(self, other: Self) -> Self { Rational{n: self.n * other.d, d: self.d * other.n}.reduced() } } impl From for Rational { fn from(v: u32) -> Self { Rational::from_int(v as i64) } } impl From for Rational { fn from(v: u16) -> Self { Rational::from_int(v as i64) } } impl From for Rational { fn from(v: u8) -> Self { Rational::from_int(v as i64) } } impl From for f64 { fn from(v: Rational) -> Self { v.n as f64 / v.d as f64 } } impl Rational { fn from_int(v: i64) -> Rational {Rational{n: v, d: 1}} fn reduced(self) -> Rational { let c = gcd(self.n, self.d); Rational{n: self.n / c, d: self.d / c} } pub fn as_int_trunc(self) -> i64 {self.n / self.d} pub fn as_int_round(self) -> i64 {(self.n as f64 / self.d as f64).round() as i64} }