use crate::error::IError;
use crate::error::IResult;
use crate::num::number::Integeral;
use crate::num::number::Number;
use crate::num::number::One;
use crate::num::number::Zero;
#[cfg(feature = "serde_mat")]
use serde::{Deserialize, Serialize};
use super::number::Equal;
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde_mat", derive(Serialize, Deserialize))]
pub struct Rational<T: Integeral> {
pub numerator: T,
pub denominator: T,
}
impl<T: Integeral> Rational<T> {
pub fn create(numerator: T, denominator: T) -> Self {
Rational {
numerator,
denominator,
}
}
pub fn refine(&self) -> IResult<Self> {
let gcd = self.numerator.gcd(&self.denominator);
let mut numerator = self.numerator.clone().ndiv(gcd.clone())?;
let mut denominator = self.denominator.clone().ndiv(gcd)?;
if (numerator < T::zero() && denominator < T::zero())
|| (numerator > T::zero() && denominator < T::zero())
{
numerator = -numerator;
denominator = -denominator;
} else if self.numerator.is_zero() {
numerator = T::zero();
denominator = T::one();
}
Ok(Self::create(numerator, denominator))
}
}
#[macro_export]
macro_rules! rat {
($x:expr, $y:expr) => {
Rational::create($x, $y)
};
}
impl<T: Integeral> std::fmt::Display for Rational<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let refined = match self.refine() {
Ok(v) => v,
Err(_) => Rational::create(T::zero(), T::zero()),
};
write!(f, "{}/{}", refined.numerator, refined.denominator)
}
}
impl<T: Integeral> std::ops::Neg for Rational<T> {
type Output = Self;
fn neg(self) -> Self::Output {
Self::create(-self.numerator, self.denominator)
}
}
impl<T: Integeral> std::ops::Add for Rational<T> {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
let numerator =
self.numerator * rhs.denominator.clone() + rhs.numerator * self.denominator.clone();
let denominator = self.denominator * rhs.denominator;
Self::create(numerator, denominator)
}
}
impl<T: Integeral> std::iter::Sum for Rational<T> {
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
iter.fold(Self::zero(), |acc, e| acc + e)
}
}
impl<T: Integeral> std::ops::Sub for Rational<T> {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
let numerator =
self.numerator * rhs.denominator.clone() - rhs.numerator * self.denominator.clone();
let denominator = self.denominator * rhs.denominator;
Self::create(numerator, denominator)
}
}
impl<T: Integeral> std::ops::Mul for Rational<T> {
type Output = Self;
fn mul(self, rhs: Self) -> Self::Output {
let numerator = self.numerator * rhs.numerator;
let denominator = self.denominator * rhs.denominator;
Self::create(numerator, denominator)
}
}
impl<T: Integeral> Default for Rational<T> {
fn default() -> Self {
Self {
numerator: T::zero(),
denominator: T::one(),
}
}
}
impl<T: Integeral> Equal for Rational<T> {
fn equal(&self, rhs: &Self) -> bool {
let self_refined = match self.refine() {
Ok(v) => v,
Err(_) => Rational::create(T::zero(), T::zero()),
};
let rhs_refined = match rhs.refine() {
Ok(v) => v,
Err(_) => Rational::create(T::zero(), T::zero()),
};
self_refined.numerator.equal(&rhs_refined.numerator)
&& self_refined.denominator.equal(&rhs_refined.denominator)
}
}
impl<T: Integeral> Zero for Rational<T> {
fn is_zero(&self) -> bool {
self.numerator.is_zero() && !self.denominator.is_zero()
}
}
impl<T: Integeral> One for Rational<T> {
fn one() -> Self {
Self::create(T::one(), T::one())
}
fn is_one(&self) -> bool {
self.numerator.gcd(&self.denominator).is_one()
}
}
impl<T: Integeral> Number for Rational<T> {
fn abs(self) -> Self {
Self::create(self.numerator.abs(), self.denominator.abs())
}
fn conjugate(self) -> Self {
rat!(self.numerator.conjugate(), self.denominator.conjugate())
}
fn ndiv(self, rhs: Self) -> IResult<Self> {
if rhs.is_zero() {
Err(IError::DividedByZero)
} else {
Ok(self * Self::create(rhs.denominator, rhs.numerator))
}
}
}