From 4d7d709b2fb8d41eaf9e4e04e43ecff0695d8414 Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 15 Apr 2017 09:37:48 -0700 Subject: [PATCH] Keep working on Numbers and stuff -- trying to get integrated with the new sibillexer crate --- types/src/lib.rs | 4 ++++ types/src/number/mod.rs | 46 +++++++++++++++++++++++++++++++++++---- types/src/number/real.rs | 47 +++++++++++++++++++++++++++------------- 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/types/src/lib.rs b/types/src/lib.rs index ff46ff0..a35f4e1 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -3,6 +3,10 @@ mod char; mod number; mod value; +pub use bool::Bool; +pub use char::Char; +pub use number::Number; + #[cfg(test)] mod tests { use bool::Bool; diff --git a/types/src/number/mod.rs b/types/src/number/mod.rs index 05ea25a..d5b24b3 100644 --- a/types/src/number/mod.rs +++ b/types/src/number/mod.rs @@ -15,10 +15,7 @@ pub use self::real::Real; pub use self::complex::Complex; use std::any::Any; -use std::fmt::Debug; -use std::ops::Deref; - -use super::value::*; +use value::*; type Int = i64; type Flt = f64; @@ -44,6 +41,29 @@ impl Number { Number::new(Real::Integer(value), None, exact) } + pub fn from_quotient(p: Int, q: Int, exact: bool) -> Number { + let real = if exact { + // Make an exact rational an integer if possible. + Real::Rational(p, q).demote() + } + else { + // Make an inexact rational an irrational. + Real::Rational(p, q).promote_once() + }; + Number::new(real, None, exact) + } + + pub fn from_float(value: Flt, exact: bool) -> Number { + let real = if exact { + // Attempt to demote irrationals. + Real::Irrational(value).demote() + } + else { + Real::Irrational(value) + }; + Number::new(real, None, exact) + } + pub fn is_exact(&self) -> bool { self.exact } } @@ -61,3 +81,21 @@ impl ValueEq for Number { impl IsBool for Number { } impl IsChar for Number { } impl IsNumber for Number { } + +#[cfg(test)] +mod tests { + use super::Number; + use super::real::Real; + + #[test] + fn exact_numbers_are_exact() { + assert!(Number::from_int(3, true).is_exact()); + assert!(!Number::from_int(3, false).is_exact()); + } + + #[test] + fn exact_irrationals_are_reduced() { + let real = Real::Rational(3, 2); + assert_eq!(Number::from_float(1.5, true), Number::new(real, None, true)); + } +} diff --git a/types/src/number/real.rs b/types/src/number/real.rs index 9bb720f..335ed8e 100644 --- a/types/src/number/real.rs +++ b/types/src/number/real.rs @@ -2,10 +2,8 @@ * Eryn Wells */ -use std::any::Any; use super::*; use number::math::*; -use value::*; #[derive(Clone, Copy, Debug)] pub enum Real { @@ -27,7 +25,7 @@ impl Real { } /// Promote a Real to the next highest type. - fn promote(self) -> Real { + pub fn promote_once(self) -> Real { match self { Real::Integer(v) => Real::Rational(v, 1), Real::Rational(p, q) => Real::Irrational(p as Flt / q as Flt), @@ -35,10 +33,29 @@ impl Real { } } + /// Demote a Real as far down the tower as possible. + /// + /// # Examples + /// + /// ``` + /// use number::real::Real; + /// + /// assert_eq!(Real::Integer(3).demote(), Real::Integer(3)); + /// assert_eq!(Real::Rational(3, 1).demote(), Real::Integer(3)); + /// assert_eq!(Real::Irrational(3.2).demote(), Real::Rational(32, 100)); + /// assert_eq!(Real::Irrational(3.0).demote(), Real::Integer(3)); + /// ``` + pub fn demote(self) -> Real { + match self.demote_once() { + Some(demoted) => demoted.demote(), + None => self, + } + } + /// Demote a Real to the next lowest type, if possible. - fn demote(self) -> Option { + pub fn demote_once(self) -> Option { match self { - Real::Integer(v) => None, + Real::Integer(_) => None, Real::Rational(p, q) => if q == 1 { Some(Real::Integer(p)) } @@ -46,7 +63,7 @@ impl Real { None }, // TODO: Convert an irrational into a fraction. - Real::Irrational(mut v) => { + Real::Irrational(v) => { let whole_part = v.trunc(); let mut p = v.fract(); let mut q = 1.0; @@ -91,12 +108,12 @@ mod tests { #[test] fn promote_to_rationals() { - assert_eq!(Real::Integer(6).promote(), Real::Rational(6, 1)); + assert_eq!(Real::Integer(6).promote_once(), Real::Rational(6, 1)); } #[test] - fn demote_to_nothing() { - assert_eq!(Real::Integer(6).demote(), None); + fn demote_to_themselves() { + assert_eq!(Real::Integer(6).demote(), Real::Integer(6)); } } @@ -116,13 +133,13 @@ mod tests { #[test] fn promote_to_irrationals() { - assert_eq!(Real::Rational(3, 2).promote(), Real::Irrational(1.5)); + assert_eq!(Real::Rational(3, 2).promote_once(), 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))); + assert_eq!(Real::Rational(3, 2).demote(), Real::Rational(3, 2)); + assert_eq!(Real::Rational(4, 1).demote(), Real::Integer(4)); } } @@ -142,13 +159,13 @@ mod tests { #[test] fn promote_to_themselves() { - assert_eq!(Real::Irrational(3.2).promote(), Real::Irrational(3.2)); + assert_eq!(Real::Irrational(3.2).promote_once(), 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))); + assert_eq!(Real::Irrational(3.2).demote(), Real::Rational(16, 5)); + assert_eq!(Real::Irrational(3.5).demote(), Real::Rational(7, 2)); } } }