diff --git a/types/src/number/frac.rs b/types/src/number/frac.rs index b175e79..ad0d746 100644 --- a/types/src/number/frac.rs +++ b/types/src/number/frac.rs @@ -5,28 +5,40 @@ use std::any::Any; use std::fmt; use std::ops::{Add, Mul}; +use number::arith::GCD; use number::{Int, Number}; use object::{Obj, Object}; /// A fraction consisting of a numerator and denominator. -#[derive(Debug, Eq, PartialEq)] -pub struct Frac(pub i64, pub u64); +#[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] +pub struct Frac(Int, Int); impl Frac { + pub fn new(p: Int, q: Int) -> Result { + if q == Int(0) { + // TODO: Return a more specific error about dividing by zero. + Err(()) + } else { + Ok(Frac(p, q).reduced()) + } + } + + fn reduced(self) -> Frac { + let gcd = self.0.gcd(self.1); + Frac(self.0 / gcd, self.1 / gcd) + } } impl Number for Frac { fn as_int(&self) -> Option { - if self.1 == 1 { - Some(Int(self.0)) + if self.1 == Int(1) { + Some(self.0) } else { None } } - fn as_frac(&self) -> Option { - Some(Frac(self.0, self.1)) - } + fn as_frac(&self) -> Option { Frac::new(self.0, self.1).ok() } } impl fmt::Display for Frac { @@ -64,25 +76,25 @@ mod tests { #[test] fn equal_fracs_are_equal() { - assert_eq!(Frac(3, 2), Frac(3, 2)); - assert_ne!(Frac(12, 4), Frac(9, 7)); + assert_eq!(Frac(Int(3), Int(2)), Frac(Int(3), Int(2))); + assert_ne!(Frac(Int(12), Int(4)), Frac(Int(9), Int(7))); } #[test] fn fracs_should_reduce_to_ints_where_possible() { - let rational_as_integer = Frac(3, 1).as_int(); + let rational_as_integer = Frac(Int(3), Int(1)).as_int(); assert!(rational_as_integer.is_some()); // Oh my god this line is so dumb. } #[test] fn fracs_should_not_reduce_to_ints_where_impossible() { - let rational_as_integer = Frac(3, 2).as_int(); + let rational_as_integer = Frac(Int(3), Int(2)).as_int(); assert!(rational_as_integer.is_none()); } #[test] fn fracs_are_exact() { - assert!(Frac(4, 2).is_exact()); + assert!(Frac(Int(4), Int(2)).is_exact()); } } diff --git a/types/src/number/integer.rs b/types/src/number/integer.rs index 98ff532..d075035 100644 --- a/types/src/number/integer.rs +++ b/types/src/number/integer.rs @@ -4,12 +4,12 @@ use std::any::Any; use std::fmt; -use std::ops::{Add, Mul, Rem}; +use std::ops::{Add, Div, Mul, Rem}; use number::arith::{GCD, LCM}; use number::{Frac, Number}; use object::{Obj, Object}; -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] pub struct Int(pub i64); impl Add for Int { @@ -39,6 +39,27 @@ impl fmt::Display for Int { } } +impl Div for Int { + type Output = Int; + fn div(self, rhs: Self) -> Self::Output { + Int(self.0 / rhs.0) + } +} + +impl<'a> Div for &'a Int { + type Output = Int; + fn div(self, rhs: Int) -> Self::Output { + Int(self.0 / rhs.0) + } +} + +impl<'a, 'b> Div<&'a Int> for &'b Int { + type Output = Int; + fn div(self, rhs: &Int) -> Self::Output { + Int(self.0 / rhs.0) + } +} + impl GCD for Int { fn gcd(self, other: Int) -> Int { let (mut a, mut b) = if self.0 > other.0 { @@ -72,7 +93,7 @@ impl Object for Int { impl Number for Int { fn as_int(&self) -> Option { Some(*self) } - fn as_frac(&self) -> Option { Some(Frac(self.0, 1)) } + fn as_frac(&self) -> Option { Frac::new(*self, Int(1)).ok() } } impl Mul for Int {