wmathrs 0.1.0

A simple mathematical crate.
Documentation
use crate::number_theory; 
use crate::scalar::{ One, Zero, Latex, Similar, Abs, Neg, Rec, Con, Pow }; 
use std::fmt::{ Formatter, Display, Result }; 
use std::cmp::{ PartialEq, Eq, PartialOrd, Ord, Ordering }; 
use std::ops::{ Add, Sub, Mul, Div }; 
use std::convert::{ From, Into }; 
use std::iter::{ Iterator, Sum }; 

#[derive(Debug, Clone, Copy)]
/// 有理数
pub struct Fraction {
    num: i128, 
    den: i128, 
}

impl Fraction {
    pub fn new(num: i128, den: i128) -> Self {
        if (num == 0) && (den == 0) { panic!("0/0 isn't a valid fraction!"); }
        let (mut num, mut den) = (num, den); 
        if den < 0 {
            num *= -1; 
            den *= -1; 
        }
        let gcd = number_theory::greatest_common_divisor(num.abs() as u128, den.abs() as u128) as i128; 
        Fraction {
            num: num / gcd, 
            den: den / gcd, 
        }
    }

    pub fn get_num(&self) -> i128 {
        self.num
    }

    pub fn get_den(&self) -> i128 {
        self.den
    }
}

#[macro_export]
/// example: frac!(4, 5) -> 4/5
macro_rules! frac {
    ($num:expr, $den:expr) =>  {
        Fraction::new($num, $den)
    }; 
    ($num:expr) => {
        Fraction::new($num, 1i128)
    }
}

impl Display for Fraction {
    fn fmt(&self, f: &mut Formatter) -> Result {
        write!(f, "{}/{}", self.num, self.den)
    }
}

impl Latex for Fraction {
    fn latex(&self) -> String {
        if self.den == 1 {
            format!("{}", self.num)
        } else {
            format!("\\frac{{{}}}{{{}}}", self.num, self.den)
        }
    }
}

impl One for Fraction {
    fn get_one(&self) -> Self {
        Fraction::new(1, 1)
    }

    fn eq_one(&self) -> bool {
        *self == Fraction::new(1, 1)
    }

    fn similar_one(&self, precision: f64) -> bool {
        let num: f64 = (*self).into(); 
        (num - 1.0).abs() < precision.abs()
    }
}

impl Zero for Fraction {
    fn get_zero(&self) -> Self {
        Fraction::new(0, 1)
    }

    fn eq_zero(&self) -> bool {
        *self == Fraction::new(0, 1)
    }

    fn similar_zero(&self, precision: f64) -> bool {
        let num: f64 = (*self).into(); 
        num.abs() < precision.abs()
    }
}

impl Abs for Fraction {
    type Output = Self; 
    fn abs(&self) -> Self {
        Fraction::new(self.num.abs(), self.den.abs())
    }
}

impl Neg for Fraction {
    type Output = Self; 
    fn neg(&self) -> Self {
        Fraction::new(-self.num, self.den)
    }
}

impl Rec for Fraction {
    type Output = Self; 
    fn rec(&self) -> Self {
        Fraction::new(self.den, self.num)
    }
}

impl Con for Fraction {
    type Output = Self; 
    fn con(&self) -> Self {
        *self
    }
}

impl Pow for Fraction {
    type Output = Self; 
    fn pow(&self, power: u32) -> Self {
        Fraction::new(self.num.pow(power), self.den.pow(power))
    }
}

impl PartialEq for Fraction {
    fn eq(&self, other: &Self) -> bool {
        self.num * other.den == self.den * other.num
    }
}

impl Eq for Fraction {}

impl PartialOrd for Fraction {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

impl Ord for Fraction {
    fn cmp(&self, other: &Self) -> Ordering {
        (self.num * other.den).cmp(&(other.num * self.den))
    }
}

impl Similar for Fraction {
    fn similar(&self, other: &Self, precision: f64) -> bool {
        let self_num: f64 = (*self).into(); 
        let other_num: f64 = (*other).into(); 
        (self_num - other_num).abs() < precision.abs()
    }
}

impl Add for Fraction {
    type Output = Self; 
    fn add(self, other: Self) -> Self {
        Fraction::new(self.num * other.den + self.den * other.num, self.den * other.den)
    }
}

impl Sub for Fraction {
    type Output = Self; 
    fn sub(self, other: Self) -> Self {
        Fraction::new(self.num * other.den - self.den * other.num, self.den * other.den)
    }
}

impl Mul for Fraction {
    type Output = Self; 
    fn mul(self, other: Self) -> Self {
        Fraction::new(self.num * other.num, self.den * other.den)
    }
}

impl Div for Fraction {
    type Output = Self; 
    fn div(self, other: Self) -> Self {
        Fraction::new(self.num * other.den, self.den * other.num)
    }
}

impl Sum for Fraction {
    fn sum<T>(iter: T) -> Self where T: Iterator<Item = Self> {
        let mut result = Fraction::new(0, 1); 
        for item in iter { result = result + item; }
        return result; 
    }
}

macro_rules! impl_mul_div_with_frac_for {
    ($($ty:ty)*) => {$(
        impl Mul<$ty> for Fraction {
            type Output = Self; 
            fn mul(self, other: $ty) -> Self::Output {
                Fraction::new(self.num * other as i128, self.den)
            }
        }
    
        impl Mul<Fraction> for $ty {
            type Output = Fraction; 
            fn mul(self, other: Fraction) -> Self::Output {
                Fraction::new(self as i128 * other.num, other.den)
            }
        }
    
        impl Div<$ty> for Fraction {
            type Output = Self; 
            fn div(self, other: $ty) -> Self::Output {
                Fraction::new(self.num, self.den * other as i128)
            }
        }
    
        impl Div<Fraction> for $ty {
            type Output = Fraction; 
            fn div(self, other: Fraction) -> Self::Output {
                Fraction::new(self as i128 * other.den, other.num)
            }
        }
    )*}
}
impl_mul_div_with_frac_for!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize); 

impl From<i128> for Fraction {
    fn from(item: i128) -> Self {
        Fraction::new(item, 1)
    }
}

impl Into<f64> for Fraction {
    fn into(self) -> f64 {
        (self.num as f64) / (self.den as f64)
    }
}