use std::ops::{Add, Div, Mul, Neg, Rem, Sub};
use std::process::Output;
use crate::math::num_theory::{gcd, gcd_euclid_iterative};
use crate::math::traits::additive::{Abs, AddId, HasPartialSign, HasSign, Sign};
#[derive(Debug, Copy, Clone, Hash)]
pub struct Fraction<T> {
p: T, q: T, }
impl<T> Fraction<T> {
pub const fn new(numerator: T, denominator: T) -> Self {
Self {p:numerator, q:denominator }
}
pub fn numerator(&self) -> &T {
&self.p
}
pub fn denominator(&self) -> &T {
&self.q
}
}
impl<T:AddId+Neg<Output=T>+Abs<Output=T>+PartialOrd+Rem<Output = T>+Clone+Div<Output = T> + HasPartialSign> Fraction<T> {
pub fn save_new(numerator: T, denominator: T) -> Self {
if denominator.is_zero() {
panic!("Denominator cannot be zero.");
}
let gcd = gcd_euclid_iterative(numerator.clone().abs(), denominator.clone().abs());
let mut p:T = numerator / gcd.clone();
let mut q:T = denominator / gcd;
if q.is_negative() {
p = -p;
q = -q;
}
Self { p, q }
}
}
impl<T: Abs<Output = T>> Abs for Fraction<T> {
type Output = Self;
fn abs(self) -> Self::Output {
Self {
p: self.p.abs(),
q: self.q,
}
}
}
impl<T:Mul<Output=T>+Add<Output=T> + Clone> Add for Fraction<T> {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
let num = self.p * other.q.clone() + other.p * self.q.clone();
let den = self.q * other.q;
Self::new(num, den)
}
}
impl<T:Neg<Output = T>> Neg for Fraction<T> {
type Output = Self;
fn neg(self) -> Self::Output {
Self {
p: -self.p,
q: self.q,
}
}
}
impl<T:Sub<Output = T>+Mul<Output=T> + Clone> Sub for Fraction<T> {
type Output = Self;
fn sub(self, other: Self) -> Self {
let num = self.p * other.q.clone() - other.p * self.q.clone();
let den = self.q * other.q;
Self::new(num, den)
}
}
impl<T:Mul<Output=T>> Mul for Fraction<T> {
type Output = Self;
fn mul(self, other: Self) -> Self::Output {
let num = self.p * other.p;
let den = self.q * other.q;
Self::new(num, den)
}
}
impl<T:Mul<Output=T>+PartialEq+AddId> Div for Fraction<T> {
type Output = Self;
fn div(self, other: Self) -> Self::Output {
let num = self.p * other.q;
let den = self.q * other.p;
Self::new(num, den)
}
}
impl<T: PartialOrd + AddId> PartialEq<Self> for Fraction<T> {
fn eq(&self, other: &Self) -> bool {
self.p == other.p
}
}
impl<T:PartialOrd+AddId> Eq for Fraction<T> {}
impl<T:PartialOrd+AddId+Mul<Output=T>+Sub<Output=T> + HasPartialSign> PartialOrd for Fraction<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
if(self.q.is_zero()||other.q.is_zero()){
return None;
}
Some(self.p.partial_cmp(&other.p).unwrap_or(std::cmp::Ordering::Equal))
}
}
impl Fraction<i64> {
pub fn to_f64(&self) -> f64 {
self.p as f64 / self.q as f64
}
pub fn to_i64(&self) -> i64 {
self.p / self.q
}
}