use crate::number::{
integer::*,
rational::*,
traits::{ConstOne, ConstZero, Ident},
};
macro_rules! impl_rational {
(many: $(($t:ident, $num:ident, $den:ident)),+) => {
$( impl_rational![single: $t, $num, $den]; )+
};
(single: $t:ident, $num:ident, $den:ident) => {
impl Rational for $t {
#[inline]
fn is_integer(&self) -> bool {
self.num % self.den.into() == $num::ZERO
}
#[inline]
fn is_proper(&self) -> bool {
self.num.0.abs() < self.den.0.get().abs()
}
#[inline]
fn is_reduced(&self) -> bool {
self.num.integer_gcd(&Into::<$num>::into(self.den)).unwrap() == $num::ONE
}
#[inline]
fn reduce(&mut self) {
let gcd_value = self.num.integer_gcd(&Into::<$num>::into(self.den)).unwrap();
self.num /= gcd_value;
{
self.den = $den::new(self.den.0.get() / gcd_value.0).unwrap();
}
}
#[inline]
fn reduced(&self) -> Self {
let gcd_value = self.num.integer_gcd(&Into::<$num>::into(self.den)).unwrap();
$t {
num: self.num / gcd_value,
den: $den::new(self.den.0.get() / gcd_value.0).unwrap(),
}
}
#[inline]
fn invert(&mut self) {
if !self.num.is_zero() {
let old_num = self.num;
self.num = self.den.into();
{ self.den = $den::new(old_num.0).unwrap(); }
}
}
#[inline]
fn inverted(&self) -> Self {
if self.num.is_zero() {
*self
} else {
$t {
num: self.den.into(),
den: $den::new(self.num.0).unwrap(),
}
}
}
}
};
}
impl_rational![
many: (Rational8, Z8, N0z8),
(Rational16, Z16, N0z16),
(Rational32, Z32, N0z32),
(Rational64, Z64, N0z64),
(Rational128, Z128, N0z128)
];
#[cfg(test)]
mod tests {
use crate::all::*;
#[test]
fn q_rational() -> NumeraResult<()> {
assert![Q8::new(0, 7)?.is_integer()];
assert![Q8::new(1, 1)?.is_integer()];
assert![Q8::new(14, 1)?.is_integer()];
assert![Q8::new(32, 8)?.is_integer()];
assert![!Q8::new(1, 2)?.is_integer()];
assert![!Q8::new(32, 9)?.is_integer()];
assert![Q8::new(3, 14)?.is_reduced()];
assert![!Q8::new(21, 98)?.is_reduced()];
assert_eq![Q8::new(21, 98)?.reduced(), Q8::new(3, 14)?];
assert_eq![Q8::new(0, 98)?.reduced(), Q8::new(0, 1)?];
assert_eq![Q8::new(21, 98)?.inverted(), Q8::new(98, 21)?];
assert_eq![Q8::new(0, 5)?.inverted(), Q8::new(0, 5)?];
Ok(())
}
}