From 403536ec4caba3b02427b254c560ad00fc71431f Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Fri, 14 Apr 2017 07:47:51 -0700 Subject: [PATCH] Lots of churn for Real --- types/src/number/real.rs | 175 ++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 94 deletions(-) diff --git a/types/src/number/real.rs b/types/src/number/real.rs index 9912151..9bb720f 100644 --- a/types/src/number/real.rs +++ b/types/src/number/real.rs @@ -4,6 +4,7 @@ use std::any::Any; use super::*; +use number::math::*; use value::*; #[derive(Clone, Copy, Debug)] @@ -13,6 +14,53 @@ pub enum Real { Irrational(Flt) } +impl Real { + /// Reduce a rational. + pub fn reduce(self) -> Real { + match self { + Real::Rational(p, q) => { + let gcd = p.gcd(q); + Real::Rational(p / gcd, q / gcd) + }, + _ => self + } + } + + /// Promote a Real to the next highest type. + fn promote(self) -> Real { + match self { + Real::Integer(v) => Real::Rational(v, 1), + Real::Rational(p, q) => Real::Irrational(p as Flt / q as Flt), + Real::Irrational(_) => self + } + } + + /// Demote a Real to the next lowest type, if possible. + fn demote(self) -> Option { + match self { + Real::Integer(v) => None, + Real::Rational(p, q) => if q == 1 { + Some(Real::Integer(p)) + } + else { + None + }, + // TODO: Convert an irrational into a fraction. + Real::Irrational(mut v) => { + let whole_part = v.trunc(); + let mut p = v.fract(); + let mut q = 1.0; + while p.fract() != 0.0 { + p *= 10.0; + q *= 10.0; + } + p += whole_part * q; + Some(Real::Rational(p as Int, q as Int).reduce()) + } + } + } +} + impl PartialEq for Real { fn eq(&self, other: &Real) -> bool { // TODO: Make comparing different variants possible. @@ -25,143 +73,82 @@ impl PartialEq for Real { } } -impl IsBool for Real { } -impl IsChar for Real { } - -impl IsNumber for Real { - fn is_number(&self) -> bool { true } - - fn is_integer(&self) -> bool { - match *self { - Real::Integer(_) => true, - _ => false - } - } - - fn is_rational(&self) -> bool { - match *self { - Real::Irrational(_) => false, - _ => true, - } - } - - fn is_real(&self) -> bool { true } -} - -impl IsExact for Real { - fn is_exact(&self) -> bool { self.is_rational() } -} - -impl Value for Real { - fn as_value(&self) -> &Value { self } -} - -impl ValueEq for Real { - fn eq(&self, other: &Value) -> bool { - other.as_any().downcast_ref::().map_or(false, |x| x == self) - } - - fn as_any(&self) -> &Any { self } -} - #[cfg(test)] mod tests { - use number::Real; - use value::*; - - #[test] - fn reals_are_numbers() { - assert!(Real::Integer(3).is_number()); - assert!(Real::Integer(3).as_value().is_number()); - } - - #[test] - fn reals_are_not_other_values() { - assert!(!Real::Integer(3).is_bool()); - assert!(!Real::Integer(3).is_char()); - assert!(!Real::Integer(3).as_value().is_bool()); - assert!(!Real::Integer(3).as_value().is_char()); - } - mod integers { - use number::*; - use value::*; + use number::real::*; #[test] fn are_equal() { assert_eq!(Real::Integer(3), Real::Integer(3)); assert_ne!(Real::Integer(12), Real::Integer(9)); - assert_eq!(Real::Integer(4).as_value(), Real::Integer(4).as_value()); - assert_ne!(Real::Integer(5).as_value(), Real::Integer(7).as_value()); } #[test] - fn are_correctly_placed_in_the_number_pyramid() { - assert!(Real::Integer(4).is_complex()); - assert!(Real::Integer(4).is_real()); - assert!(Real::Integer(4).is_rational()); - assert!(Real::Integer(4).is_integer()); - assert!(Real::Integer(4).is_number()); + fn reduce_to_themselves() { + assert_eq!(Real::Integer(4).reduce(), Real::Integer(4)); } - + #[test] - fn are_exact() { - assert!(Real::Integer(3).is_exact()); - assert!(!Real::Integer(3).is_inexact()); + fn promote_to_rationals() { + assert_eq!(Real::Integer(6).promote(), Real::Rational(6, 1)); + } + + #[test] + fn demote_to_nothing() { + assert_eq!(Real::Integer(6).demote(), None); } } mod rationals { - use number::*; - use value::*; + use number::real::*; #[test] fn are_equal() { assert_eq!(Real::Rational(3, 2), Real::Rational(3, 2)); assert_ne!(Real::Rational(12, 4), Real::Rational(9, 7)); - assert_eq!(Real::Rational(4, 5).as_value(), Real::Rational(4, 5).as_value()); - assert_ne!(Real::Rational(5, 6).as_value(), Real::Rational(7, 6).as_value()); } #[test] - fn are_correctly_placed_in_the_number_pyramid() { - assert!(Real::Rational(4, 3).is_complex()); - assert!(Real::Rational(4, 3).is_real()); - assert!(Real::Rational(4, 3).is_rational()); - assert!(!Real::Rational(4, 3).is_integer()); + fn reduce_correctly() { + assert_eq!(Real::Rational(2, 4).reduce(), Real::Rational(1, 2)); } #[test] - fn are_exact() { - assert!(Real::Rational(3, 5).is_exact()); - assert!(!Real::Rational(3, 5).is_inexact()); + fn promote_to_irrationals() { + assert_eq!(Real::Rational(3, 2).promote(), Real::Irrational(1.5)); + } + + #[test] + fn demote_to_integers_if_possible() { + assert_eq!(Real::Rational(3, 2).demote(), None); + assert_eq!(Real::Rational(4, 1).demote(), Some(Real::Integer(4))); } } mod irrationals { - use number::*; - use value::*; + use number::real::*; #[test] fn are_equal() { assert_eq!(Real::Irrational(3.2), Real::Irrational(3.2)); assert_ne!(Real::Irrational(12.0), Real::Irrational(9.0)); - assert_eq!(Real::Irrational(4.0).as_value(), Real::Irrational(4.0).as_value()); - assert_ne!(Real::Irrational(5.0).as_value(), Real::Irrational(7.0).as_value()); } #[test] - fn are_correctly_placed_in_the_number_pyramid() { - assert!(Real::Irrational(4.0).is_complex()); - assert!(Real::Irrational(4.0).is_real()); - assert!(!Real::Irrational(4.0).is_rational()); - assert!(!Real::Irrational(4.0).is_integer()); + fn reduce_to_themselves() { + assert_eq!(Real::Irrational(3.2).reduce(), Real::Irrational(3.2)); } #[test] - fn are_inexact() { - assert!(Real::Irrational(3.0).is_inexact()); - assert!(!Real::Irrational(3.0).is_exact()); + fn promote_to_themselves() { + assert_eq!(Real::Irrational(3.2).promote(), Real::Irrational(3.2)); + } + + #[test] + fn demote_to_rationals() { + assert_eq!(Real::Irrational(3.2).demote(), Some(Real::Rational(16, 5))); + assert_eq!(Real::Irrational(3.5).demote(), Some(Real::Rational(7, 2))); } } }