From 6baf62e8c238304fb77eeb3563aa7048d0ecc57e Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Tue, 11 Apr 2017 21:32:02 -0700 Subject: [PATCH] Move Real to its own module and bring a bunch of stuff from rational and integer over --- types/src/number/mod.rs | 19 ++-- types/src/number/real.rs | 189 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 202 insertions(+), 6 deletions(-) create mode 100644 types/src/number/real.rs diff --git a/types/src/number/mod.rs b/types/src/number/mod.rs index e27eb7d..8d63841 100644 --- a/types/src/number/mod.rs +++ b/types/src/number/mod.rs @@ -6,11 +6,9 @@ /// /// Scheme numbers are complex, literally. -pub mod integer; -pub mod rational; +pub mod real; -pub use self::integer::Integer; -pub use self::rational::Rational; +pub use self::real::Real; use std::any::Any; use std::fmt::Debug; @@ -24,7 +22,9 @@ type Flt = f64; trait Number: Debug + IsBool + IsChar + IsNumber + Value { /// Convert a Number to the next lowest type in Scheme's number pyramid, if possible. fn convert_down(&self) -> Option>; +} +trait IsExact { /// Should return `true` if this Number is represented exactly. This should be an inverse of /// `is_inexact()`. fn is_exact(&self) -> bool { false } @@ -49,6 +49,13 @@ impl ValueEq for Box { fn as_any(&self) -> &Any { self } } -struct Real(Flt); -struct Complex<'a>(&'a Number, &'a Number); +#[derive(Debug, PartialEq)] +struct Complex { + real: Real, + imag: Real +} + +impl IsNumber for Complex { + fn is_complex(&self) -> bool { true } +} diff --git a/types/src/number/real.rs b/types/src/number/real.rs new file mode 100644 index 0000000..c943c4d --- /dev/null +++ b/types/src/number/real.rs @@ -0,0 +1,189 @@ +/* types/src/number/real.rs + * Eryn Wells + */ + +use std::any::Any; +use std::ops::{Add, Sub, Mul, Div}; +use super::*; +use value::*; + +#[derive(Debug)] +pub enum Real { + Integer(Int), + Rational(Int, Int), + Irrational(Flt) +} + +impl PartialEq for Real { + fn eq(&self, other: &Real) -> bool { + match *other { + Real::Integer(v) => self.eq_integer(v), + Real::Rational(p, q) => self.eq_rational(p, q), + Real::Irrational(v) => self.eq_irrational(v) + } + } +} + +impl Real { + fn eq_integer(&self, v_other: Int) -> bool { + match *self { + Real::Integer(v) => v == v_other, + _ => false + } + } + + fn eq_rational(&self, p_other: Int, q_other: Int) -> bool { + match *self { + Real::Rational(p, q) => p == p_other && q == q_other, + _ => false + } + } + + fn eq_irrational(&self, v_other: Flt) -> bool { + match *self { + Real::Irrational(v) => v == v_other, + _ => false + } + } +} + +impl IsBool for Real { } +impl IsChar for Real { } + +impl IsNumber for Real { + fn is_number(&self) -> 9bool { 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::*; + + #[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()); + } + + #[test] + fn are_exact() { + assert!(Real::Integer(3).is_exact()); + assert!(!Real::Integer(3).is_inexact()); + } + } + + mod rationals { + use number::*; + use value::*; + + #[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()); + } + + #[test] + fn are_exact() { + assert!(Real::Rational(3, 5).is_exact()); + assert!(!Real::Rational(3, 5).is_inexact()); + } + } + + mod irrationals { + use number::*; + use value::*; + + #[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()); + } + + #[test] + fn are_inexact() { + assert!(Real::Irrational(3.0).is_inexact()); + assert!(!Real::Irrational(3.0).is_exact()); + } + } +}