rusty-numbers/src/rational.rs

93 lines
1.8 KiB
Rust
Raw Normal View History

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 {}