[types] Make math ops macros even more generic -- implement them for cross types too!

Still need to write tests for this though.
This commit is contained in:
Eryn Wells 2018-09-13 18:08:14 -07:00
parent 9d40cdd995
commit c07e6aa99b
5 changed files with 33 additions and 18 deletions

View file

@ -3,7 +3,7 @@
*/
use std::ops::{Add, Div, Mul, Sub, Rem};
use number::{Int, Irr};
use number::{Int, Irr, Number};
pub trait GCD {
/// Find the greatest common divisor of `self` and another number.
@ -17,24 +17,19 @@ pub trait LCM {
macro_rules! impl_newtype_arith_op {
($id:ident, $opt:ident, $opm:ident, $op:tt) => {
impl $opt for $id {
impl<T> $opt<T> for $id where T: Number + Into<$id> {
type Output = $id;
#[inline]
fn $opm(self, rhs: $id) -> Self::Output {
fn $opm(self, rhs: T) -> Self::Output {
let rhs: $id = rhs.into();
$id(self.0 $op rhs.0)
}
}
impl<'a> $opt<$id> for &'a $id {
impl<'a, T> $opt<T> for &'a $id where T: Number + Into<$id> {
type Output = $id;
#[inline]
fn $opm(self, rhs: $id) -> Self::Output {
$id(self.0 $op rhs.0)
}
}
impl<'a, 'b> $opt<&'a $id> for &'b $id {
type Output = $id;
#[inline]
fn $opm(self, rhs: &$id) -> Self::Output {
fn $opm(self, rhs: T) -> Self::Output {
let rhs: $id = rhs.into();
$id(self.0 $op rhs.0)
}
}

View file

@ -32,6 +32,10 @@ impl Frac {
Frac::new(Int(p), Int(q))
}
pub fn quotient(&self) -> f64 {
self.p.0 as f64 / self.q.0 as f64
}
fn reduced(self) -> Frac {
let gcd = self.p.gcd(self.q);
Frac { p: self.p / gcd, q: self.q / gcd }
@ -77,6 +81,12 @@ impl fmt::Display for Frac {
}
}
impl From<Int> for Frac {
fn from(i: Int) -> Frac {
Frac{p: i, q: Int(1)}
}
}
impl Mul for Frac {
type Output = Frac;
fn mul(self, rhs: Self) -> Self::Output {

View file

@ -5,8 +5,8 @@
use std::any::Any;
use std::fmt;
use number::arith::{GCD, LCM};
use number::{Frac, Number};
use object::{Obj, Object};
use super::{Frac, Number};
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct Int(pub i64);

View file

@ -20,9 +20,14 @@ impl fmt::Display for Irr {
}
}
impl Object for Irr {
fn as_any(&self) -> &Any { self }
fn as_num(&self) -> Option<&Number> { Some(self) }
impl From<Int> for Irr {
fn from(i: Int) -> Irr { Irr(i.0 as f64) }
}
impl From<Frac> for Irr {
fn from(f: Frac) -> Irr {
Irr(f.quotient())
}
}
impl Number for Irr {
@ -46,6 +51,11 @@ impl Number for Irr {
fn is_zero(&self) -> bool { self.0 == 0.0 }
}
impl Object for Irr {
fn as_any(&self) -> &Any { self }
fn as_num(&self) -> Option<&Number> { Some(self) }
}
impl PartialEq<Obj> for Irr {
fn eq<'a>(&self, rhs: &'a Obj) -> bool {
match rhs.obj().and_then(Object::as_num) {

View file

@ -11,13 +11,13 @@
//! Integer can be cast as a Rational (by putting its value over 1), but a Rational like 1/2 cannot
//! be represented as an Integer.
use object::Object;
mod arith;
mod frac;
mod integer;
mod irr;
use object::Object;
pub use self::frac::Frac;
pub use self::integer::Int;
pub use self::irr::Irr;