rusty-numbers/src/rational.rs

93 lines
1.8 KiB
Rust

//! # Rational Numbers (fractions)
//!
//! Traits to implement:
//! * Add
//! * AddAssign
//! * Div
//! * DivAssign
//! * Mul
//! * MulAssign
//! * Neg
//! * Sub
//! * SubAssign
use crate::{Sign, Unsigned};
use std::ops::{Mul, Neg};
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
pub struct Frac<T: Unsigned = usize> {
numer: T,
denom: T,
sign: Sign,
}
impl<T: Unsigned> Frac<T> {
/// Create a new rational number
pub fn new(n: T, d: T) -> Self {
if d.is_zero() {
panic!("Fraction can not have a zero denominator");
}
Frac {
numer: n,
denom: d,
sign: Sign::Positive,
}
.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
}
}
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);
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
}
}
#[cfg(test)]
mod tests {}