use std::ops; //TODO slow ? check Stein's algorithm (binaryGCD) fn gcd(a: i128, b: i128) -> i128 { if b == 0 { a } else { gcd(b, a % b) } } #[derive(Debug, PartialEq, Clone, Copy)] pub struct Rational { numerator: i128, denominator: i128, } impl Rational { pub fn new(numerator: i128, denominator: i128) -> Self { Self { numerator, denominator, } } pub fn reduce(&self) -> Self { let gcd = gcd(self.numerator, self.denominator); Rational::new(self.numerator / gcd, self.denominator / gcd) } pub fn inverse(&self) -> Self { Rational::new(self.denominator, self.numerator) } } impl ops::Add for Rational { type Output = Rational; fn add(self, rhs: Rational) -> Rational { Rational::new(self.numerator * rhs.denominator + rhs.numerator * self.denominator, self.denominator * rhs.denominator).reduce() } } impl ops::Add for Rational { type Output = Rational; fn add(self, rhs: i128) -> Rational { Rational::new(self.numerator + rhs * self.denominator, self.denominator).reduce() } } impl ops::Add for i128 { type Output = Rational; fn add(self, rhs: Rational) -> Rational { Rational::new(self * rhs.denominator + rhs.numerator, rhs.denominator).reduce() } } impl ops::Sub for Rational { type Output = Rational; fn sub(self, rhs: Rational) -> Rational { Rational::new(self.numerator * rhs.denominator - rhs.numerator * self.denominator, self.denominator * rhs.denominator).reduce() } } impl ops::Sub for Rational { type Output = Rational; fn sub(self, rhs: i128) -> Rational { Rational::new(self.numerator - rhs * self.denominator, self.denominator).reduce() } } impl ops::Sub for i128 { type Output = Rational; fn sub(self, rhs: Rational) -> Rational { Rational::new(self * rhs.denominator - rhs.numerator, rhs.denominator).reduce() } } impl ops::Mul for Rational { type Output = Rational; fn mul(self, rhs: Rational) -> Rational { Rational::new(self.numerator * rhs.numerator, self.denominator * rhs.denominator).reduce() } } impl ops::Mul for Rational { type Output = Rational; fn mul(self, rhs: i128) -> Rational { Rational::new(self.numerator * rhs, self.denominator).reduce() } } impl ops::Mul for i128 { type Output = Rational; fn mul(self, rhs: Rational) -> Rational { Rational::new(self * rhs.numerator, rhs.denominator).reduce() } } impl ops::Div for Rational { type Output = Rational; fn div(self, rhs: Rational) -> Rational { self * rhs.inverse() } } impl ops::Div for Rational { type Output = Rational; fn div(self, rhs: i128) -> Rational { let rhs_inverse = Rational::new(1, rhs); self * rhs_inverse } } impl ops::Div for i128 { type Output = Rational; fn div(self, rhs: Rational) -> Rational { self * rhs.inverse() } } #[derive(Debug, PartialEq, Clone, Copy)] pub struct GaussianRational { real: Rational, imaginary: Rational, } impl GaussianRational { pub fn new(real: Rational, imaginary: Rational) -> Self { Self { real, imaginary, } } pub fn conjugate(&self) -> Self { GaussianRational::new(self.real, -1 * self.imaginary) } } impl ops::Add for GaussianRational { type Output = GaussianRational; fn add(self, rhs: GaussianRational) -> GaussianRational { GaussianRational::new(self.real + rhs.real, self.imaginary + rhs.imaginary) } } impl ops::Sub for GaussianRational { type Output = GaussianRational; fn sub(self, rhs: GaussianRational) -> GaussianRational { GaussianRational::new(self.real - rhs.real, self.imaginary - rhs.imaginary) } } impl ops::Mul for GaussianRational { type Output = GaussianRational; fn mul(self, rhs: GaussianRational) -> GaussianRational { GaussianRational::new(self.real * rhs.real - self.imaginary * self.imaginary, self.real * rhs.imaginary + self.imaginary * rhs.real) } }