Keep working on Numbers and stuff -- trying to get integrated with the new sibillexer crate

This commit is contained in:
Eryn Wells 2017-04-15 09:37:48 -07:00
parent fc947280ae
commit 4d7d709b2f
3 changed files with 78 additions and 19 deletions

View file

@ -3,6 +3,10 @@ mod char;
mod number; mod number;
mod value; mod value;
pub use bool::Bool;
pub use char::Char;
pub use number::Number;
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use bool::Bool; use bool::Bool;

View file

@ -15,10 +15,7 @@ pub use self::real::Real;
pub use self::complex::Complex; pub use self::complex::Complex;
use std::any::Any; use std::any::Any;
use std::fmt::Debug; use value::*;
use std::ops::Deref;
use super::value::*;
type Int = i64; type Int = i64;
type Flt = f64; type Flt = f64;
@ -44,6 +41,29 @@ impl Number {
Number::new(Real::Integer(value), None, exact) 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 } pub fn is_exact(&self) -> bool { self.exact }
} }
@ -61,3 +81,21 @@ impl ValueEq for Number {
impl IsBool for Number { } impl IsBool for Number { }
impl IsChar for Number { } impl IsChar for Number { }
impl IsNumber 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));
}
}

View file

@ -2,10 +2,8 @@
* Eryn Wells <eryn@erynwells.me> * Eryn Wells <eryn@erynwells.me>
*/ */
use std::any::Any;
use super::*; use super::*;
use number::math::*; use number::math::*;
use value::*;
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub enum Real { pub enum Real {
@ -27,7 +25,7 @@ impl Real {
} }
/// Promote a Real to the next highest type. /// Promote a Real to the next highest type.
fn promote(self) -> Real { pub fn promote_once(self) -> Real {
match self { match self {
Real::Integer(v) => Real::Rational(v, 1), Real::Integer(v) => Real::Rational(v, 1),
Real::Rational(p, q) => Real::Irrational(p as Flt / q as Flt), 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. /// Demote a Real to the next lowest type, if possible.
fn demote(self) -> Option<Real> { pub fn demote_once(self) -> Option<Real> {
match self { match self {
Real::Integer(v) => None, Real::Integer(_) => None,
Real::Rational(p, q) => if q == 1 { Real::Rational(p, q) => if q == 1 {
Some(Real::Integer(p)) Some(Real::Integer(p))
} }
@ -46,7 +63,7 @@ impl Real {
None None
}, },
// TODO: Convert an irrational into a fraction. // TODO: Convert an irrational into a fraction.
Real::Irrational(mut v) => { Real::Irrational(v) => {
let whole_part = v.trunc(); let whole_part = v.trunc();
let mut p = v.fract(); let mut p = v.fract();
let mut q = 1.0; let mut q = 1.0;
@ -91,12 +108,12 @@ mod tests {
#[test] #[test]
fn promote_to_rationals() { 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] #[test]
fn demote_to_nothing() { fn demote_to_themselves() {
assert_eq!(Real::Integer(6).demote(), None); assert_eq!(Real::Integer(6).demote(), Real::Integer(6));
} }
} }
@ -116,13 +133,13 @@ mod tests {
#[test] #[test]
fn promote_to_irrationals() { 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] #[test]
fn demote_to_integers_if_possible() { fn demote_to_integers_if_possible() {
assert_eq!(Real::Rational(3, 2).demote(), None); assert_eq!(Real::Rational(3, 2).demote(), Real::Rational(3, 2));
assert_eq!(Real::Rational(4, 1).demote(), Some(Real::Integer(4))); assert_eq!(Real::Rational(4, 1).demote(), Real::Integer(4));
} }
} }
@ -142,13 +159,13 @@ mod tests {
#[test] #[test]
fn promote_to_themselves() { 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] #[test]
fn demote_to_rationals() { fn demote_to_rationals() {
assert_eq!(Real::Irrational(3.2).demote(), Some(Real::Rational(16, 5))); assert_eq!(Real::Irrational(3.2).demote(), Real::Rational(16, 5));
assert_eq!(Real::Irrational(3.5).demote(), Some(Real::Rational(7, 2))); assert_eq!(Real::Irrational(3.5).demote(), Real::Rational(7, 2));
} }
} }
} }