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 value;
pub use bool::Bool;
pub use char::Char;
pub use number::Number;
#[cfg(test)]
mod tests {
use bool::Bool;

View file

@ -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));
}
}

View file

@ -2,10 +2,8 @@
* Eryn Wells <eryn@erynwells.me>
*/
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<Real> {
pub fn demote_once(self) -> Option<Real> {
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));
}
}
}