#[cfg(doc)]
use crate::NumError::{self, Overflow};
use crate::{Frac, Int, IntResult as Result};
macro_rules! impl_frac {
[] => {
impl_frac![i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize];
};
($( $i:ty),+ ) => {
$(
impl_frac![@array $i, [$i; 2], Frac<[$i; 2]>];
impl_frac![@int_array $i, [Int<$i>; 2], Frac<[Int<$i>; 2]>];
)+
};
(@array $i:ty, $self:ty, $fout:ty) => { $crate::paste! {
#[doc = "# Fraction related methods for `[" $i "; 2]`\n\n"]
impl Frac<$self> {
#[must_use]
pub const fn numerator(self) -> $i { self.0[0] }
#[must_use]
pub const fn num(self) -> $i { self.0[0] }
#[must_use]
pub const fn denominator(self) -> $i { self.0[1] }
#[must_use]
pub const fn den(self) -> $i { self.0[0] }
#[doc = "assert![Frac([2_" $i ", 1]).is_valid()];"]
#[doc = "assert![!Frac([2_" $i ", 0]).is_valid()];"]
#[must_use]
pub const fn is_valid(self) -> bool { self.0[1] != 0 }
#[doc = "assert![Frac([2_" $i ", 3]).is_proper()];"]
#[doc = "assert![!Frac([3_" $i ", 3]).is_proper()];"]
#[doc = "assert![!Frac([4_" $i ", 3]).is_proper()];"]
#[must_use]
pub const fn is_proper(self) -> bool { Int(self.0[0]).abs().0 < Int(self.0[1]).abs().0 }
#[must_use]
pub const fn is_reduced(self) -> bool { self.gcd() == 1 }
pub const fn reduce(self) -> $fout {
let g = self.gcd();
Frac([self.0[0] / g, self.0[1] / g])
}
#[must_use]
pub const fn gcd(self) -> $i { Int(self.0[0]).gcd(self.0[1]).0 }
pub const fn lcm(self) -> Result<$i> {
match Int(self.numerator()).lcm(self.denominator()) {
Ok(res) => Ok(res.0),
Err(e) => Err(e)
}
}
#[allow(clippy::should_implement_trait)]
pub fn add(self, other: $self) -> Result<$fout> {
let [num1, den1, num2, den2] = [self.0[0], self.0[1], other[0], other[1]];
let lcm_denom = match Int(den1).lcm(den2) {
Ok(res) => res.0,
Err(e) => { return Err(e); }
};
let num = num1 * (lcm_denom / den1) + num2 * (lcm_denom / den2);
Ok(Frac([num, lcm_denom]).reduce())
}
}
}};
(@int_array $i:ty, $self:ty, $fout:ty) => { $crate::paste! {
#[doc = "# Fraction related methods for `[Int<" $i ">; 2]`\n\n"]
impl Frac<$self> {
pub const fn numerator(self) -> Int<$i> { self.0[0] }
pub const fn denominator(self) -> Int<$i> { self.0[1] }
#[doc = "assert![Frac([Int(2_" $i "), Int(1)]).is_valid()];"]
#[doc = "assert![!Frac([Int(2_" $i "), Int(0)]).is_valid()];"]
#[must_use]
pub const fn is_valid(self) -> bool { self.0[1].0 != 0 }
#[doc = "assert![Frac([Int(2_" $i "), Int(3)]).is_proper()];"]
#[doc = "assert![!Frac([Int(3_" $i "), Int(3)]).is_proper()];"]
#[doc = "assert![!Frac([Int(4_" $i "), Int(3)]).is_proper()];"]
#[must_use]
pub const fn is_proper(self) -> bool { self.0[0].abs().0 < self.0[1].abs().0 }
#[must_use]
pub const fn is_reduced(self) -> bool { self.gcd().0 == 1 }
pub const fn reduce(self) -> $fout {
let g = self.gcd().0;
Frac([Int(self.0[0].0 / g), Int(self.0[1].0 / g)])
}
pub const fn gcd(self) -> Int<$i> { self.0[0].gcd(self.0[1].0) }
pub const fn lcm(self) -> Result<Int<$i>> {
match self.numerator().lcm(self.denominator().0) {
Ok(res) => Ok(res),
Err(e) => Err(e)
}
}
#[allow(clippy::should_implement_trait)]
pub fn add(self, other: $self) -> Result<$fout> {
let [num1, den1, num2, den2] = [self.0[0].0, self.0[1].0, other[0].0, other[1].0];
let lcm_denom = match Int(den1).lcm(den2) {
Ok(res) => res.0,
Err(e) => { return Err(e); }
};
let num = num1 * (lcm_denom / den1) + num2 * (lcm_denom / den2);
Ok(Frac([Int(num), Int(lcm_denom)]).reduce())
}
}
}};
}
impl_frac!();