implement operator overloading for comparision operators
Some checks failed
timw4mail/rusty-numbers/pipeline/head There was a failure building this commit

This commit is contained in:
Timothy Warren 2020-02-18 20:59:58 -05:00
parent caeb1879c4
commit 2f8b61dab5

View File

@ -1,6 +1,7 @@
//! # Rational Numbers (fractions) //! # Rational Numbers (fractions)
use crate::num::*; use crate::num::*;
use std::cmp::{Ord, Ordering, PartialOrd};
use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
/// Type representing a fraction /// Type representing a fraction
@ -104,7 +105,65 @@ impl<T: Unsigned> Frac<T> {
} }
} }
impl<T: Unsigned + Mul<Output = T>> Mul for Frac<T> { impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> PartialOrd
for Frac<T>
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
fn lt(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Less
}
fn le(&self, other: &Self) -> bool {
self == other || self.cmp(other) == Ordering::Less
}
fn gt(&self, other: &Self) -> bool {
self.cmp(other) == Ordering::Greater
}
fn ge(&self, other: &Self) -> bool {
self == other || self.cmp(other) == Ordering::Greater
}
}
impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> Ord
for Frac<T>
{
fn cmp(&self, other: &Self) -> Ordering {
if self.sign == other.sign {
if self.denom == other.denom {
return self.numer.cmp(&other.numer);
} else {
let gcd = T::gcd(self.denom, other.denom);
let x = gcd / self.denom;
let y = gcd / self.denom;
let mut a = self.clone();
let mut b = other.clone();
a.numer *= x;
a.denom *= x;
b.numer *= y;
b.denom *= y;
a.numer.cmp(&b.numer)
}
} else {
if self.sign == Sign::Positive {
return Ordering::Greater;
} else {
return Ordering::Less;
}
}
}
}
impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> Mul
for Frac<T>
{
type Output = Self; type Output = Self;
fn mul(self, rhs: Self) -> Self { fn mul(self, rhs: Self) -> Self {
@ -116,13 +175,17 @@ impl<T: Unsigned + Mul<Output = T>> Mul for Frac<T> {
} }
} }
impl<T: Unsigned + Mul<Output = T>> MulAssign for Frac<T> { impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> MulAssign
for Frac<T>
{
fn mul_assign(&mut self, rhs: Self) { fn mul_assign(&mut self, rhs: Self) {
*self = self.clone() * rhs *self = self.clone() * rhs
} }
} }
impl<T: Unsigned + Mul<Output = T>> Div for Frac<T> { impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> Div
for Frac<T>
{
type Output = Self; type Output = Self;
fn div(self, rhs: Self) -> Self { fn div(self, rhs: Self) -> Self {
@ -134,13 +197,17 @@ impl<T: Unsigned + Mul<Output = T>> Div for Frac<T> {
} }
} }
impl<T: Unsigned + Mul<Output = T>> DivAssign for Frac<T> { impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> DivAssign
for Frac<T>
{
fn div_assign(&mut self, rhs: Self) { fn div_assign(&mut self, rhs: Self) {
*self = self.clone() / rhs *self = self.clone() / rhs
} }
} }
impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T>> Add for Frac<T> { impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> Add
for Frac<T>
{
type Output = Self; type Output = Self;
fn add(self, rhs: Self) -> Self::Output { fn add(self, rhs: Self) -> Self::Output {
@ -150,9 +217,9 @@ impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T>> Add for
// If the sign of one input differs, // If the sign of one input differs,
// subtraction is equivalent // subtraction is equivalent
if self.sign != rhs.sign { if self.sign != rhs.sign {
if a.numer > b.numer { if a > b {
return a - b; return a - b;
} else if a.numer < b.numer { } else if a < b {
return b - a; return b - a;
} }
} }
@ -176,20 +243,25 @@ impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T>> Add for
} }
} }
impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T>> AddAssign for Frac<T> { impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> AddAssign
for Frac<T>
{
fn add_assign(&mut self, rhs: Self) { fn add_assign(&mut self, rhs: Self) {
*self = self.clone() + rhs *self = self.clone() + rhs
} }
} }
impl<T: Unsigned + Sub<Output = T> + Mul<Output = T>> Sub for Frac<T> { impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> Sub
for Frac<T>
{
type Output = Self; type Output = Self;
fn sub(self, rhs: Self) -> Self::Output { fn sub(self, rhs: Self) -> Self::Output {
// Set the larger argument as `a` let a = self;
let a = self;
let b = rhs; let b = rhs;
// @TODO handle sign "overflow" conditions
if a.denom != b.denom { if a.denom != b.denom {
let numer = (a.numer * b.denom) - (b.numer * a.denom); let numer = (a.numer * b.denom) - (b.numer * a.denom);
let denom = a.denom * b.denom; let denom = a.denom * b.denom;
@ -206,7 +278,9 @@ impl<T: Unsigned + Sub<Output = T> + Mul<Output = T>> Sub for Frac<T> {
} }
} }
impl<T: Unsigned + Sub<Output = T> + Mul<Output = T>> SubAssign for Frac<T> { impl<T: Unsigned + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> SubAssign
for Frac<T>
{
fn sub_assign(&mut self, rhs: Self) { fn sub_assign(&mut self, rhs: Self) {
*self = self.clone() - rhs *self = self.clone() - rhs
} }
@ -247,8 +321,8 @@ mod tests {
#[test] #[test]
fn sub_test() { fn sub_test() {
assert_eq!(frac!(1 / 6), frac!(1 / 2) - frac!(1 / 3)); assert_eq!(frac!(1 / 6), frac!(1 / 2) - frac!(1 / 3));
// assert_eq!(frac!(1), frac!(1/3) - -frac!(2/3), "1/3 - -2/3"); // assert_eq!(frac!(1), frac!(1 / 3) - -frac!(2 / 3), "1/3 - -2/3");
// assert_eq!(-frac!(1 / 1), -frac!(2 / 3) - frac!(1 / 3), "-2/3 - 1/3"); // assert_eq!(-frac!(1), -frac!(2 / 3) - frac!(1 / 3), "-2/3 - 1/3");
} }
#[test] #[test]