2020-02-12 23:10:08 -05:00
|
|
|
//! # Rational Numbers (fractions)
|
|
|
|
//!
|
|
|
|
//! Traits to implement:
|
|
|
|
//! * Add
|
|
|
|
//! * AddAssign
|
|
|
|
//! * Div
|
|
|
|
//! * DivAssign
|
|
|
|
//! * Mul
|
|
|
|
//! * MulAssign
|
|
|
|
//! * Neg
|
|
|
|
//! * Sub
|
|
|
|
//! * SubAssign
|
2020-02-12 22:29:57 -05:00
|
|
|
|
2020-02-12 23:10:08 -05:00
|
|
|
use crate::{Sign, Unsigned};
|
2020-02-13 17:13:25 -05:00
|
|
|
use std::ops::{Mul, Neg};
|
2020-02-12 23:10:08 -05:00
|
|
|
|
2020-02-13 17:13:25 -05:00
|
|
|
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
|
2020-02-12 22:29:57 -05:00
|
|
|
pub struct Frac<T: Unsigned = usize> {
|
|
|
|
numer: T,
|
|
|
|
denom: T,
|
2020-02-12 23:10:08 -05:00
|
|
|
sign: Sign,
|
2020-02-12 22:29:57 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<T: Unsigned> Frac<T> {
|
|
|
|
/// Create a new rational number
|
|
|
|
pub fn new(n: T, d: T) -> Self {
|
2020-02-13 17:13:25 -05:00
|
|
|
if d.is_zero() {
|
|
|
|
panic!("Fraction can not have a zero denominator");
|
|
|
|
}
|
|
|
|
|
2020-02-12 22:29:57 -05:00
|
|
|
Frac {
|
|
|
|
numer: n,
|
|
|
|
denom: d,
|
2020-02-12 23:10:08 -05:00
|
|
|
sign: Sign::Positive,
|
2020-02-12 22:29:57 -05:00
|
|
|
}
|
2020-02-13 17:13:25 -05:00
|
|
|
.reduce()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn new_neg(n: T, d: T) -> Self {
|
|
|
|
let mut frac = Frac::new(n, d);
|
|
|
|
frac.sign = Sign::Negative;
|
|
|
|
|
|
|
|
frac
|
|
|
|
}
|
|
|
|
|
|
|
|
fn reduce(mut self) -> Self {
|
|
|
|
let gcd = T::gcd(self.numer, self.denom);
|
|
|
|
self.numer /= gcd;
|
|
|
|
self.denom /= gcd;
|
|
|
|
|
|
|
|
self
|
2020-02-12 22:29:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-13 17:13:25 -05:00
|
|
|
macro_rules! impl_mul {
|
|
|
|
($Type: ty) => {
|
|
|
|
impl Mul for Frac<$Type> {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn mul(self, rhs: Self) -> Self {
|
|
|
|
let numer = self.numer * rhs.numer;
|
|
|
|
let denom = self.denom * rhs.denom;
|
|
|
|
|
|
|
|
// Figure out the sign
|
|
|
|
if self.sign != rhs.sign {
|
|
|
|
Self::new_neg(numer, denom)
|
|
|
|
} else {
|
|
|
|
Self::new(numer, denom)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
impl_mul!(u8);
|
|
|
|
impl_mul!(u16);
|
|
|
|
impl_mul!(u32);
|
|
|
|
impl_mul!(u64);
|
|
|
|
impl_mul!(usize);
|
|
|
|
|
2020-02-12 23:10:08 -05:00
|
|
|
impl<T: Unsigned> Neg for Frac<T> {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn neg(self) -> Self::Output {
|
|
|
|
let mut out = self.clone();
|
|
|
|
out.sign = !self.sign;
|
|
|
|
|
|
|
|
out
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 22:29:57 -05:00
|
|
|
#[cfg(test)]
|
2020-02-13 17:13:25 -05:00
|
|
|
mod tests {}
|