From fb9cc03bb9464299d504b74230e70afd5adfe288 Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 8 Apr 2023 20:26:07 -0700 Subject: [PATCH] Reorganized quantity --- src/parser/mod.rs | 4 +- src/quantity/mod.rs | 88 +--- src/quantity/quantity.rs | 445 +++++------------- src/quantity/{f64q.rs => scalar/f64base.rs} | 93 ++-- .../{floatq.rs => scalar/floatbase.rs} | 103 ++-- src/quantity/scalar/mod.rs | 382 +++++++++++++++ .../{rationalq.rs => scalar/rationalbase.rs} | 128 +++-- src/tokens/operator.rs | 22 +- 8 files changed, 655 insertions(+), 610 deletions(-) rename src/quantity/{f64q.rs => scalar/f64base.rs} (59%) rename src/quantity/{floatq.rs => scalar/floatbase.rs} (74%) create mode 100644 src/quantity/scalar/mod.rs rename src/quantity/{rationalq.rs => scalar/rationalbase.rs} (69%) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 783653c..dd9d305 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -98,13 +98,13 @@ impl PreToken { // Units "m" => { - let mut u = Quantity::new_rational(1, 1); + let mut u = Quantity::new_rational_from_string("1").unwrap(); u.add_unit(BaseUnit::Meter, 1f64); Token::Number(u) }, "s" => { - let mut u = Quantity::new_rational(1, 1); + let mut u = Quantity::new_rational_from_string("1").unwrap(); u.add_unit(BaseUnit::Second, 1f64); Token::Number(u) } diff --git a/src/quantity/mod.rs b/src/quantity/mod.rs index 18b7aa2..f1c149f 100644 --- a/src/quantity/mod.rs +++ b/src/quantity/mod.rs @@ -1,12 +1,3 @@ -use std::ops::{ - Add, Sub, Mul, Div, - Neg, Rem, - - AddAssign, SubAssign, - MulAssign, DivAssign -}; - - /* Quantity: Represents a value with a unit attached to it. @@ -24,82 +15,13 @@ The cfg_if blocks here are a temporary hack to allow for cross-compilation to other systems. RUG does not work on all systems. */ -pub mod quantity; +mod scalar; +pub(in crate::quantity) use crate::quantity::scalar::Scalar; + + mod unit; pub use crate::quantity::unit::Unit; pub use crate::quantity::unit::BaseUnit; -cfg_if::cfg_if! { - if #[cfg(target_family = "unix")] { - mod rationalq; - mod floatq; - } else { - mod f64q; - } -} - -macro_rules! wrap_rational { - ( $x:expr, $y:expr ) => { Quantity::Rational{v: $x, u: $y} } -} - -macro_rules! wrap_float { - ( $x:expr, $y:expr ) => { Quantity::Float{v: $x, u: $y} } -} - +mod quantity; pub use crate::quantity::quantity::Quantity; -pub(in crate::quantity) use wrap_rational; -pub(in crate::quantity) use wrap_float; - - -const FLOAT_PRECISION: u32 = 1024; -const PRINT_LEN: usize = 5; // How many significant digits we will show in output - - -pub trait RationalBase: QuantBase { - fn from_frac(top: i64, bot: i64) -> Self; - fn from_f64(f: f64) -> Option where Self: Sized; - fn from_string(s: &str) -> Optionwhere Self: Sized; -} - -pub trait FloatBase: QuantBase { - fn from_f64(f: f64) -> Option where Self: Sized; - fn from_string(s: &str) -> Option where Self: Sized; -} - -pub trait QuantBase: - Sized + ToString + - Add + AddAssign + - Sub + SubAssign + - Mul + MulAssign + - Div + DivAssign + - Neg + Rem + - PartialEq + PartialOrd -{ - fn fract(&self) -> Option; - fn is_zero(&self) -> bool; - fn is_negative(&self) -> bool; - fn is_positive(&self) -> bool; - - fn exp(&self) -> Option; - fn abs(&self) -> Option; - fn floor(&self) -> Option; - fn ceil(&self) -> Option; - fn round(&self) -> Option; - fn sin(&self) -> Option; - fn cos(&self) -> Option; - fn tan(&self) -> Option; - fn asin(&self) -> Option; - fn acos(&self) -> Option; - fn atan(&self) -> Option; - fn sinh(&self) -> Option; - fn cosh(&self) -> Option; - fn tanh(&self) -> Option; - fn asinh(&self) -> Option; - fn acosh(&self) -> Option; - fn atanh(&self) -> Option; - fn ln(&self) -> Option; - fn log10(&self) -> Option; - fn log2(&self) -> Option; - fn log(&self, base: Self) -> Option; - fn pow(&self, exp: Self) -> Option; -} \ No newline at end of file diff --git a/src/quantity/quantity.rs b/src/quantity/quantity.rs index 70b1e99..0c6c166 100644 --- a/src/quantity/quantity.rs +++ b/src/quantity/quantity.rs @@ -7,171 +7,85 @@ use std::ops::{ }; use std::cmp::Ordering; -use crate::quantity::wrap_rational; -use crate::quantity::wrap_float; - -use crate::quantity::QuantBase; -use crate::quantity::RationalBase; -use crate::quantity::FloatBase; use crate::quantity::Unit; use crate::quantity::BaseUnit; -cfg_if::cfg_if! { - if #[cfg(target_family = "unix")] { - use crate::quantity::rationalq::RationalQ; - use crate::quantity::floatq::FloatQ; - #[derive(Debug)] - #[derive(Clone)] - pub enum Quantity { - Rational{ v: RationalQ, u: Unit }, - Float{ v: FloatQ, u: Unit } - } - } else { - use crate::quantity::f64q::F64Q; +use crate::quantity::Scalar; - #[derive(Debug)] - #[derive(Clone)] - pub enum Quantity { - Rational{ v: F64Q, u: Unit }, - Float{ v: F64Q, u: Unit } - } - } -} - - -impl Quantity { - - cfg_if::cfg_if! { - if #[cfg(target_family = "unix")] { - pub fn new_rational(top: i64, bottom: i64) -> Quantity { - return wrap_rational!( - RationalQ::from_frac(top, bottom), - Unit::new() - ); - } - - pub fn new_float(v: f64) -> Quantity { - return wrap_float!( - FloatQ::from_f64(v).unwrap(), - Unit::new() - ) - } - - pub fn new_rational_from_string(s: &str) -> Option { - let r = RationalQ::from_string(s); - if r.is_none() { return None; } - return Some(wrap_rational!( - r.unwrap(), - Unit::new() - )); - } - - pub fn new_float_from_string(s: &str) -> Option { - let v = FloatQ::from_string(s); - if v.is_none() { return None; } - return Some(wrap_float!( - v.unwrap(), - Unit::new() - )) - } - - pub fn float_from_rat(r: &Quantity) -> Quantity { - match &r { - Quantity::Float { .. } => r.clone(), - Quantity::Rational { v, u } => wrap_float!( - FloatQ::from(v.val.numer()).unwrap() / - FloatQ::from(v.val.denom()).unwrap(), - u.clone() - ) - } - } - } else { - pub fn new_rational(top: i64, bottom: i64) -> Quantity { - return wrap_float!(F64Q::from_f64( (top as f64) / (bottom as f64)).unwrap()) - } - - pub fn new_float(v: f64) -> Quantity { - return wrap_float!(F64Q::from_f64(v).unwrap()) - } - - pub fn new_rational_from_string(s: &str) -> Option { - let r = F64Q::from_string(s); - if r.is_none() { return None; } - return Some(wrap_rational!(r.unwrap())); - } - - pub fn new_float_from_string(s: &str) -> Option { - let v = F64Q::from_string(s); - if v.is_none() { return None; } - return Some(wrap_float!(v.unwrap())) - } - - pub fn float_from_rat(r: &Quantity) -> Quantity { - match &r { - Quantity::Float { .. } => r.clone(), - Quantity::Rational { .. } => r.clone() - } - } - } - } - - pub fn is_nan(&self) -> bool { - match self { - Quantity::Float { v, .. } => {v.val.is_nan()}, - Quantity::Rational { .. } => {panic!()} - } - } - - pub fn add_unit(&mut self, ui: BaseUnit, pi: f64) { - match self { - Quantity::Float { u, .. } => {u.insert(ui, pi)}, - Quantity::Rational { u, .. } => {u.insert(ui, pi)} - } - } +#[derive(Debug)] +#[derive(Clone)] +pub struct Quantity { + v: Scalar, + u: Unit } impl ToString for Quantity { fn to_string(&self) -> String { - let mut n: String; - let u: &Unit; - match self { - Quantity::Rational{u:un, ..} => { - n = Quantity::float_from_rat(self).to_string(); - u = un - }, - Quantity::Float{v, u:un} => { - n = v.to_string(); - u = un; - }, - }; - + let n = self.v.to_string(); //n.push(' '); //n.push_str(&u.to_string()); n } } +impl Quantity { + pub fn new_float(f: f64) -> Option { + let v = Scalar::new_float(f); + if v.is_none() { return None; } + + return Some(Quantity{ + v: v.unwrap(), + u: Unit::new() + }); + } + + pub fn new_rational(f: f64) -> Option { + let v = Scalar::new_rational(f); + if v.is_none() { return None; } + + return Some(Quantity{ + v: v.unwrap(), + u: Unit::new() + }); + } + + pub fn new_float_from_string(s: &str) -> Option { + let v = Scalar::new_float_from_string(s); + if v.is_none() { return None; } + + return Some(Quantity{ + v: v.unwrap(), + u: Unit::new() + }); + } + + pub fn new_rational_from_string(s: &str) -> Option { + let v = Scalar::new_rational_from_string(s); + if v.is_none() { return None; } + + return Some(Quantity{ + v: v.unwrap(), + u: Unit::new() + }); + } + + pub fn add_unit(&mut self, ui: BaseUnit, pi: f64) { + self.u.insert(ui, pi) + } +} + macro_rules! quant_foward { ( $x:ident ) => { pub fn $x(&self) -> Quantity { - match self { - Quantity::Rational{v, u} => { - if !u.unitless() { panic!() } - let r = v.$x(); - if r.is_none() { - let v = Quantity::float_from_rat(self); - return v.$x(); - } else {wrap_rational!(r.unwrap(), u.clone())} - }, - Quantity::Float{v, u} => { - if !u.unitless() { panic!() } - wrap_float!(v.$x().unwrap(), u.clone()) - }, + if !self.unitless() { panic!() } + Quantity { + v: self.v.$x(), + u: self.u.clone() } } } @@ -179,33 +93,11 @@ macro_rules! quant_foward { impl Quantity { - pub fn is_zero(&self) -> bool { - match self { - Quantity::Rational{v, .. } => v.is_zero(), - Quantity::Float{v, .. } => v.is_zero(), - } - } - - pub fn is_negative(&self) -> bool { - match self { - Quantity::Rational{v, .. } => v.is_negative(), - Quantity::Float{v, .. } => v.is_negative(), - } - } - - pub fn is_positive(&self) -> bool { - match self { - Quantity::Rational{v, .. } => v.is_positive(), - Quantity::Float{v, .. } => v.is_positive(), - } - } - - pub fn unitless(&self) -> bool { - match self { - Quantity::Rational{ u, .. } => u.unitless(), - Quantity::Float{ u, .. } => u.unitless(), - } - } + pub fn is_zero(&self) -> bool { self.v.is_zero() } + pub fn is_nan(&self) -> bool { self.v.is_nan() } + pub fn is_negative(&self) -> bool { self.v.is_negative() } + pub fn is_positive(&self) -> bool { self.v.is_positive() } + pub fn unitless(&self) -> bool { self.u.unitless() } quant_foward!(fract); quant_foward!(abs); @@ -230,67 +122,30 @@ impl Quantity { quant_foward!(log2); pub fn log(&self, base: Quantity) -> Quantity { - if !self.unitless() { panic!() } - - match self { - Quantity::Rational{u, .. } => { - if !u.unitless() { panic!() } - Quantity::float_from_rat(self).log(Quantity::float_from_rat(&base)) - }, - Quantity::Float{u, .. } => { - if !u.unitless() { panic!() } - Quantity::float_from_rat(self).log(base) - }, + Quantity { + v: self.v.log(base.v), + u: self.u.clone() } } - pub fn pow(&self, base: Quantity) -> Quantity { - match self { - Quantity::Rational{u, .. } => { - let a = match Quantity::float_from_rat(self) { - Quantity::Rational{ .. } => panic!(), - Quantity::Float{v, .. } => v, - }; - let b = match Quantity::float_from_rat(&base) { - Quantity::Rational{ .. } => panic!(), - Quantity::Float{v, .. } => v, - }; - - let mut nu = u.clone(); - nu.pow(2f64); - wrap_float!(a.pow(b).unwrap(), nu) - }, - Quantity::Float{u, .. } => { - if !u.unitless() { panic!() } - - let a = match Quantity::float_from_rat(self) { - Quantity::Rational{ .. } => panic!(), - Quantity::Float{v, .. } => v, - }; - - let b = match Quantity::float_from_rat(&base) { - Quantity::Rational{ .. } => panic!(), - Quantity::Float{v, .. } => v, - }; - let mut nu = u.clone(); - nu.pow(2f64); - wrap_float!(a.pow(b).unwrap(), nu) - - }, + pub fn pow(&self, pwr: Quantity) -> Quantity { + if !self.unitless() { panic!() } + Quantity { + v: self.v.pow(pwr.v), + u: self.u.clone() } } } - impl Neg for Quantity where { type Output = Self; fn neg(self) -> Self::Output { - match self { - Quantity::Float { v, u } => {wrap_float!(-v, u)}, - Quantity::Rational { v, u } => {wrap_rational!(-v, u)}, + Quantity { + v: -self.v, + u: self.u } } } @@ -299,35 +154,19 @@ impl Add for Quantity { type Output = Self; fn add(self, other: Self) -> Self::Output { - match (&self, &other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - if ua != ub { panic!() } - wrap_float!(va.clone()+vb.clone(), ua.clone()) - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {self + Quantity::float_from_rat(&other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {Quantity::float_from_rat(&self) + other}, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - if ua != ub { panic!() } - wrap_rational!(va.clone()+vb.clone(), ua.clone()) - }, + if self.u != other.u { panic!() } + + Quantity { + v: self.v + other.v, + u: self.u } } } impl AddAssign for Quantity where { fn add_assign(&mut self, other: Self) { - match (&mut *self, &other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - if ua != ub { panic!() } - *va += vb.clone() - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {*self += Quantity::float_from_rat(&other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {*self = Quantity::float_from_rat(self) + other }, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - if ua != ub { panic!() } - *va += vb.clone() - }, - } + if self.u != other.u { panic!() } + self.v += other.v } } @@ -335,35 +174,19 @@ impl Sub for Quantity { type Output = Self; fn sub(self, other: Self) -> Self::Output { - match (&self, &other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - if ua != ub { panic!() } - wrap_float!(va.clone()-vb.clone(), ua.clone()) - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {self - Quantity::float_from_rat(&other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {Quantity::float_from_rat(&self) - other}, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - if ua != ub { panic!() } - wrap_rational!(va.clone()-vb.clone(), ua.clone()) - }, + if self.u != other.u { panic!() } + + Quantity { + v: self.v - other.v, + u: self.u } } } impl SubAssign for Quantity where { fn sub_assign(&mut self, other: Self) { - match (&mut *self, &other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - if ua != ub { panic!() } - *va -= vb.clone() - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {*self -= Quantity::float_from_rat(&other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {*self = Quantity::float_from_rat(self) - other }, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - if ua != ub { panic!() } - *va -= vb.clone() - }, - } + if self.u != other.u { panic!() } + self.v -= other.v } } @@ -371,35 +194,17 @@ impl Mul for Quantity { type Output = Self; fn mul(self, other: Self) -> Self::Output { - match (&self, &other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - let u = ua.clone()*ub.clone(); - wrap_float!(va.clone()*vb.clone(), u) - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {self * Quantity::float_from_rat(&other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {Quantity::float_from_rat(&self) * self}, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - let u = ua.clone()*ub.clone(); - wrap_rational!(va.clone()*vb.clone(), u) - }, + Quantity { + v: self.v * other.v, + u: self.u * other.u } } } impl MulAssign for Quantity where { fn mul_assign(&mut self, other: Self) { - match (&mut *self, &other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - *ua *= ub.clone(); - *va *= vb.clone() - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {*self *= Quantity::float_from_rat(&other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {*self = Quantity::float_from_rat(self) * other }, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - *ua *= ub.clone(); - *va *= vb.clone() - }, - } + self.v *= other.v; + self.u *= other.u; } } @@ -407,35 +212,17 @@ impl Div for Quantity { type Output = Self; fn div(self, other: Self) -> Self::Output { - match (&self, &other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - let u = ua.clone()/ub.clone(); - wrap_float!(va.clone()/vb.clone(), u) - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {self / Quantity::float_from_rat(&other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {Quantity::float_from_rat(&self) / other}, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - let u = ua.clone()/ub.clone(); - wrap_rational!(va.clone()/vb.clone(), u) - }, + Quantity { + v: self.v / other.v, + u: self.u / other.u } } } impl DivAssign for Quantity where { fn div_assign(&mut self, other: Self) { - match (&mut *self, &other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - *ua /= ub.clone(); - *va /= vb.clone() - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {*self /= Quantity::float_from_rat(&other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {*self = Quantity::float_from_rat(self) / other }, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - *ua /= ub.clone(); - *va /= vb.clone() - } - } + self.v /= other.v; + self.u /= other.u; } } @@ -443,45 +230,27 @@ impl Rem for Quantity { type Output = Self; fn rem(self, other: Quantity) -> Self::Output { - match (&self, &other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - if ua != ub { panic!() } - wrap_float!(va.clone()%vb.clone(), ua.clone()) - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {self % Quantity::float_from_rat(&other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {Quantity::float_from_rat(&self) % other}, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - if ua != ub { panic!() } - wrap_rational!(va.clone()%vb.clone(), ua.clone()) - }, + if !self.u.unitless() { panic!() } + if !other.u.unitless() { panic!() } + + Quantity { + v: self.v % other.v, + u: self.u } } } impl PartialEq for Quantity { fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { if ua!=ub {false} else {va == vb} }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {*self == Quantity::float_from_rat(other)}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {Quantity::float_from_rat(self) == *other}, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { if ua!=ub {false} else {va == vb} }, + if self.u != other.u {false} else { + self.v == other.v } } } impl PartialOrd for Quantity { fn partial_cmp(&self, other: &Self) -> Option { - match (self, other) { - (Quantity::Float{v:va,u:ua}, Quantity::Float{v:vb,u:ub}) => { - if ua != ub { panic!() } - va.partial_cmp(vb) - }, - (Quantity::Float{ .. }, Quantity::Rational{ .. }) => {(*self).partial_cmp(&Quantity::float_from_rat(other))}, - (Quantity::Rational{ .. }, Quantity::Float{ .. }) => {Quantity::float_from_rat(self).partial_cmp(other)}, - (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { - if ua != ub { panic!() } - va.partial_cmp(vb) - }, - } + if self.u != other.u { panic!() } + self.v.partial_cmp(&other.v) } } \ No newline at end of file diff --git a/src/quantity/f64q.rs b/src/quantity/scalar/f64base.rs similarity index 59% rename from src/quantity/f64q.rs rename to src/quantity/scalar/f64base.rs index 3511f00..f672214 100644 --- a/src/quantity/f64q.rs +++ b/src/quantity/scalar/f64base.rs @@ -7,33 +7,43 @@ use std::ops::{ }; use std::cmp::Ordering; - -use crate::quantity::wrap_float; -use crate::quantity::Quantity; -use crate::quantity::QuantBase; -use crate::quantity::FloatBase; +use super::ScalarBase; macro_rules! foward { ( $x:ident ) => { - fn $x(&self) -> Quantity { - wrap_float!(F64Q{ val: self.val.clone().$x() }) + fn $x(&self) -> Option { + Some(F64Base{ val: self.val.clone().$x() }) } } } #[derive(Debug)] #[derive(Clone)] -pub struct F64Q where { +pub struct F64Base where { pub val: f64 } -impl ToString for F64Q { +impl ToString for F64Base { fn to_string(&self) -> String { self.val.to_string() } } -impl QuantBase for F64Q { +impl ScalarBase for F64Base { + + fn from_f64(f: f64) -> Option { + return Some(F64Base{ val: f }); + } + + fn from_string(s: &str) -> Option { + let v = s.parse::(); + let v = match v { + Ok(x) => x, + Err(_) => return None + }; + + return Some(F64Base{ val: v }); + } foward!(fract); @@ -65,40 +75,17 @@ impl QuantBase for F64Q { foward!(log10); foward!(log2); - fn log(&self, base: Quantity) -> Quantity { - wrap_float!(F64Q{ val: self.val.clone().log10() }) / - Quantity::float_from_rat(&base).log10() + fn log(&self, base: Self) -> Option { + Some(F64Base{ val: self.val.clone().log10() } / base.log10().unwrap()) } - fn pow(&self, base: Quantity) -> Quantity { - match base { - Quantity::Rational { .. } => self.pow(Quantity::float_from_rat(&base)), - Quantity::Float { v } => wrap_float!(F64Q{ val: self.val.clone().powf(v.val) }) - } - + fn pow(&self, base: Self) -> Option { + Some(F64Base{ val: self.val.clone().powf(base.val)}) } } -impl FloatBase for F64Q { - fn from_f64(f: f64) -> Option { - return Some(F64Q{ val: f }); - } - - fn from_string(s: &str) -> Option { - let v = s.parse::(); - let v = match v { - Ok(x) => x, - Err(_) => return None - }; - - return Some(F64Q{ val: v }); - } -} - - - -impl Add for F64Q where { +impl Add for F64Base where { type Output = Self; fn add(self, other: Self) -> Self::Output { @@ -106,13 +93,13 @@ impl Add for F64Q where { } } -impl AddAssign for F64Q where { +impl AddAssign for F64Base where { fn add_assign(&mut self, other: Self) { self.val += other.val; } } -impl Sub for F64Q { +impl Sub for F64Base { type Output = Self; fn sub(self, other: Self) -> Self::Output { @@ -120,13 +107,13 @@ impl Sub for F64Q { } } -impl SubAssign for F64Q where { +impl SubAssign for F64Base where { fn sub_assign(&mut self, other: Self) { self.val -= other.val; } } -impl Mul for F64Q { +impl Mul for F64Base { type Output = Self; fn mul(self, other: Self) -> Self::Output { @@ -134,13 +121,13 @@ impl Mul for F64Q { } } -impl MulAssign for F64Q where { +impl MulAssign for F64Base where { fn mul_assign(&mut self, other: Self) { self.val *= other.val; } } -impl Div for F64Q { +impl Div for F64Base { type Output = Self; fn div(self, other: Self) -> Self::Output { @@ -148,13 +135,13 @@ impl Div for F64Q { } } -impl DivAssign for F64Q where { +impl DivAssign for F64Base where { fn div_assign(&mut self, other: Self) { self.val /= other.val; } } -impl Neg for F64Q where { +impl Neg for F64Base where { type Output = Self; fn neg(self) -> Self::Output { @@ -162,26 +149,26 @@ impl Neg for F64Q where { } } -impl Rem for F64Q { +impl Rem for F64Base { type Output = Self; - fn rem(self, modulus: F64Q) -> Self::Output { + fn rem(self, modulus: F64Base) -> Self::Output { if { - (!self.fract().is_zero()) || - (!modulus.fract().is_zero()) + (!self.fract().unwrap().is_zero()) || + (!modulus.fract().unwrap().is_zero()) } { panic!() } - F64Q{val : self.val.fract() % modulus.val.fract()} + F64Base{val : self.val.fract() % modulus.val.fract()} } } -impl PartialEq for F64Q { +impl PartialEq for F64Base { fn eq(&self, other: &Self) -> bool { self.val == other.val } } -impl PartialOrd for F64Q { +impl PartialOrd for F64Base { fn partial_cmp(&self, other: &Self) -> Option { self.val.partial_cmp(&other.val) } diff --git a/src/quantity/floatq.rs b/src/quantity/scalar/floatbase.rs similarity index 74% rename from src/quantity/floatq.rs rename to src/quantity/scalar/floatbase.rs index a2d275e..cb31f84 100644 --- a/src/quantity/floatq.rs +++ b/src/quantity/scalar/floatbase.rs @@ -13,37 +13,35 @@ use std::ops::{ use std::cmp::Ordering; -use crate::quantity::QuantBase; -use crate::quantity::FloatBase; -use crate::quantity::PRINT_LEN; - +use super::ScalarBase; +use super::PRINT_LEN; use super::FLOAT_PRECISION; macro_rules! foward { ( $x:ident ) => { - fn $x(&self) -> Option { - Some(FloatQ{ val: self.val.clone().$x()}) + fn $x(&self) -> Option { + Some(FloatBase{ val: self.val.clone().$x()}) } } } #[derive(Debug)] #[derive(Clone)] -pub struct FloatQ where { +pub struct FloatBase where { pub val: Float } -impl FloatQ { - pub fn from(a: T) -> Option where +impl FloatBase { + pub fn from(a: T) -> Option where Float: Assign + AssignRound { let v = Float::with_val(FLOAT_PRECISION, a); - return Some(FloatQ{ val: v }); + return Some(FloatBase{ val: v }); } } -impl ToString for FloatQ { +impl ToString for FloatBase { fn to_string(&self) -> String { let (sign, mut string, exp) = self.val.to_sign_string_exp(10, Some(PRINT_LEN)); @@ -57,9 +55,9 @@ impl ToString for FloatQ { while string.chars().last().unwrap() == '0' { string.remove(string.len() - 1); } - + let exp_u: usize; - + if exp < 0 { exp_u = (-exp).try_into().unwrap() } else { @@ -101,7 +99,26 @@ impl ToString for FloatQ { } -impl QuantBase for FloatQ { +impl ScalarBase for FloatBase { + + fn from_f64(f: f64) -> Option { + let v = Float::with_val(FLOAT_PRECISION, f); + return Some(FloatBase{ val: v }); + } + + fn from_string(s: &str) -> Option { + let v = Float::parse(s); + let v = match v { + Ok(x) => x, + Err(_) => return None + }; + + return Some( + FloatBase{ val: + Float::with_val(FLOAT_PRECISION, v) + } + ); + } foward!(fract); @@ -133,40 +150,18 @@ impl QuantBase for FloatQ { foward!(log10); foward!(log2); - fn log(&self, base: FloatQ) -> Option { - Some(FloatQ{ val: self.val.clone().log10() } / base.log10().unwrap()) + fn log(&self, base: FloatBase) -> Option { + Some(FloatBase{ val: self.val.clone().log10() } / base.log10().unwrap()) } - fn pow(&self, base: FloatQ) -> Option { - Some(FloatQ{ val: self.val.clone().pow(base.val)}) + fn pow(&self, base: FloatBase) -> Option { + Some(FloatBase{ val: self.val.clone().pow(base.val)}) } } -impl FloatBase for FloatQ { - fn from_f64(f: f64) -> Option { - let v = Float::with_val(FLOAT_PRECISION, f); - return Some(FloatQ{ val: v }); - } - fn from_string(s: &str) -> Option { - let v = Float::parse(s); - let v = match v { - Ok(x) => x, - Err(_) => return None - }; - - return Some( - FloatQ{ val: - Float::with_val(FLOAT_PRECISION, v) - } - ); - } -} - - - -impl Add for FloatQ where { +impl Add for FloatBase where { type Output = Self; fn add(self, other: Self) -> Self::Output { @@ -174,13 +169,13 @@ impl Add for FloatQ where { } } -impl AddAssign for FloatQ where { +impl AddAssign for FloatBase where { fn add_assign(&mut self, other: Self) { self.val += other.val; } } -impl Sub for FloatQ { +impl Sub for FloatBase { type Output = Self; fn sub(self, other: Self) -> Self::Output { @@ -188,13 +183,13 @@ impl Sub for FloatQ { } } -impl SubAssign for FloatQ where { +impl SubAssign for FloatBase where { fn sub_assign(&mut self, other: Self) { self.val -= other.val; } } -impl Mul for FloatQ { +impl Mul for FloatBase { type Output = Self; fn mul(self, other: Self) -> Self::Output { @@ -202,13 +197,13 @@ impl Mul for FloatQ { } } -impl MulAssign for FloatQ where { +impl MulAssign for FloatBase where { fn mul_assign(&mut self, other: Self) { self.val *= other.val; } } -impl Div for FloatQ { +impl Div for FloatBase { type Output = Self; fn div(self, other: Self) -> Self::Output { @@ -216,13 +211,13 @@ impl Div for FloatQ { } } -impl DivAssign for FloatQ where { +impl DivAssign for FloatBase where { fn div_assign(&mut self, other: Self) { self.val /= other.val; } } -impl Neg for FloatQ where { +impl Neg for FloatBase where { type Output = Self; fn neg(self) -> Self::Output { @@ -230,26 +225,26 @@ impl Neg for FloatQ where { } } -impl Rem for FloatQ { +impl Rem for FloatBase { type Output = Self; - fn rem(self, modulus: FloatQ) -> Self::Output { + fn rem(self, modulus: FloatBase) -> Self::Output { if { (!self.fract().unwrap().is_zero()) || (!modulus.fract().unwrap().is_zero()) } { panic!() } - FloatQ{val : self.val.fract() % modulus.val.fract()} + FloatBase{val : self.val.fract() % modulus.val.fract()} } } -impl PartialEq for FloatQ { +impl PartialEq for FloatBase { fn eq(&self, other: &Self) -> bool { self.val == other.val } } -impl PartialOrd for FloatQ { +impl PartialOrd for FloatBase { fn partial_cmp(&self, other: &Self) -> Option { self.val.partial_cmp(&other.val) } diff --git a/src/quantity/scalar/mod.rs b/src/quantity/scalar/mod.rs new file mode 100644 index 0000000..4092860 --- /dev/null +++ b/src/quantity/scalar/mod.rs @@ -0,0 +1,382 @@ +use std::ops::{ + Add, Sub, Mul, Div, + Neg, Rem, + + AddAssign, SubAssign, + MulAssign, DivAssign +}; +use std::cmp::Ordering; + + +pub trait ScalarBase: + Sized + ToString + + Add + AddAssign + + Sub + SubAssign + + Mul + MulAssign + + Div + DivAssign + + Neg + Rem + + PartialEq + PartialOrd +{ + // Creation + fn from_f64(f: f64) -> Option; + fn from_string(s: &str) -> Option; + + // Utility + fn fract(&self) -> Option; + fn is_zero(&self) -> bool; + fn is_negative(&self) -> bool; + fn is_positive(&self) -> bool; + + // Mathematical + fn exp(&self) -> Option; + fn abs(&self) -> Option; + fn floor(&self) -> Option; + fn ceil(&self) -> Option; + fn round(&self) -> Option; + fn sin(&self) -> Option; + fn cos(&self) -> Option; + fn tan(&self) -> Option; + fn asin(&self) -> Option; + fn acos(&self) -> Option; + fn atan(&self) -> Option; + fn sinh(&self) -> Option; + fn cosh(&self) -> Option; + fn tanh(&self) -> Option; + fn asinh(&self) -> Option; + fn acosh(&self) -> Option; + fn atanh(&self) -> Option; + fn ln(&self) -> Option; + fn log10(&self) -> Option; + fn log2(&self) -> Option; + fn log(&self, base: Self) -> Option; + fn pow(&self, exp: Self) -> Option; +} + + +const FLOAT_PRECISION: u32 = 1024; +const PRINT_LEN: usize = 5; // How many significant digits we will show in output + +mod rationalbase; +mod floatbase; +//mod f64base; +use self::rationalbase::RationalBase; +use self::floatbase::FloatBase as FloatBase; + + + + +#[derive(Debug)] +#[derive(Clone)] +pub enum Scalar { + Rational{ v: RationalBase }, + Float{ v: FloatBase } +} + + +macro_rules! wrap_rational { + ( $x:expr) => { Scalar::Rational{v: $x} } +} + +macro_rules! wrap_float { + ( $x:expr) => { Scalar::Float{v: $x} } +} + + +fn to_float(r: Scalar) -> Scalar { + match &r { + Scalar::Float {..} => r, + Scalar::Rational {v} => wrap_float!( + FloatBase::from(v.val.numer()).unwrap() / + FloatBase::from(v.val.denom()).unwrap() + ) + } +} + +impl ToString for Scalar { + fn to_string(&self) -> String { + match self { + Scalar::Rational{..} => to_float(self.clone()).to_string(), + Scalar::Float{v} => v.to_string() + } + } +} + +// Creation methods +impl Scalar { + pub fn new_float(f: f64) -> Option { + let v = FloatBase::from_f64(f); + if v.is_none() { return None; } + return Some(wrap_float!(v.unwrap())); + } + + pub fn new_rational(f: f64) -> Option { + let r = RationalBase::from_f64(f); + if r.is_none() { return None; } + return Some(wrap_rational!(r.unwrap())); + } + + pub fn new_rational_from_string(s: &str) -> Option { + let r = RationalBase::from_string(s); + if r.is_none() { return None; } + return Some(wrap_rational!(r.unwrap())); + } + + pub fn new_float_from_string(s: &str) -> Option { + let v = FloatBase::from_string(s); + if v.is_none() { return None; } + return Some(wrap_float!(v.unwrap())) + } +} + +impl Scalar { + pub fn is_nan(&self) -> bool { + match self { + Scalar::Float {v} => {v.val.is_nan()}, + Scalar::Rational {..} => {panic!()} + } + } +} + +// Forwarded functions +macro_rules! scalar_foward { + ( $x:ident ) => { + pub fn $x(&self) -> Scalar { + match self { + Scalar::Rational{v} => { + let r = v.$x(); + if r.is_none() { + let v = to_float(self.clone()); + return v.$x(); + } else {wrap_rational!(r.unwrap())} + }, + Scalar::Float{v} => {wrap_float!(v.$x().unwrap())}, + } + } + } +} + +impl Scalar { + pub fn is_zero(&self) -> bool { + match self { + Scalar::Rational{v} => v.is_zero(), + Scalar::Float{v} => v.is_zero(), + } + } + + pub fn is_negative(&self) -> bool { + match self { + Scalar::Rational{v} => v.is_negative(), + Scalar::Float{v} => v.is_negative(), + } + } + + pub fn is_positive(&self) -> bool { + match self { + Scalar::Rational{v} => v.is_positive(), + Scalar::Float{v} => v.is_positive(), + } + } + + scalar_foward!(fract); + scalar_foward!(abs); + scalar_foward!(floor); + scalar_foward!(ceil); + scalar_foward!(round); + scalar_foward!(sin); + scalar_foward!(cos); + scalar_foward!(tan); + scalar_foward!(asin); + scalar_foward!(acos); + scalar_foward!(atan); + scalar_foward!(sinh); + scalar_foward!(cosh); + scalar_foward!(tanh); + scalar_foward!(asinh); + scalar_foward!(acosh); + scalar_foward!(atanh); + scalar_foward!(exp); + scalar_foward!(ln); + scalar_foward!(log10); + scalar_foward!(log2); + + pub fn log(&self, base: Scalar) -> Scalar { + match self { + Scalar::Rational{..} => { to_float(self.clone()).log(to_float(base)) }, + Scalar::Float{..} => { to_float(self.clone()).log(to_float(base)) }, + } + } + + pub fn pow(&self, base: Scalar) -> Scalar { + match self { + Scalar::Rational{..} => { + let a = match to_float(self.clone()) { + Scalar::Rational{..} => panic!(), + Scalar::Float{v} => v, + }; + + let b = match to_float(base) { + Scalar::Rational{..} => panic!(), + Scalar::Float{v} => v, + }; + + wrap_float!(a.pow(b).unwrap()) + }, + Scalar::Float{..} => { + let a = match to_float(self.clone()) { + Scalar::Rational{..} => panic!(), + Scalar::Float{v} => v, + }; + + let b = match to_float(base) { + Scalar::Rational{..} => panic!(), + Scalar::Float{v} => v, + }; + + wrap_float!(a.pow(b).unwrap()) + + }, + } + } +} + +impl Neg for Scalar where { + type Output = Self; + + fn neg(self) -> Self::Output { + match self { + Scalar::Float { v } => {wrap_float!(-v)}, + Scalar::Rational { v } => {wrap_rational!(-v)}, + } + } +} + +impl Add for Scalar { + type Output = Self; + + fn add(self, other: Self) -> Self::Output { + match (&self, &other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {wrap_float!(va.clone()+vb.clone())}, + (Scalar::Float{..}, Scalar::Rational{..}) => {self + to_float(other)}, + (Scalar::Rational{..}, Scalar::Float{..}) => {to_float(self) + other}, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {wrap_rational!(va.clone()+vb.clone())}, + } + } +} + +impl AddAssign for Scalar where { + fn add_assign(&mut self, other: Self) { + match (&mut *self, &other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {*va += vb.clone()}, + (Scalar::Float{..}, Scalar::Rational{..}) => {*self += to_float(other)}, + (Scalar::Rational{..}, Scalar::Float{..}) => {*self = to_float(self.clone()) + other }, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {*va += vb.clone()}, + } + } +} + +impl Sub for Scalar { + type Output = Self; + + fn sub(self, other: Self) -> Self::Output { + match (&self, &other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {wrap_float!(va.clone()-vb.clone())}, + (Scalar::Float{..}, Scalar::Rational{..}) => {self - to_float(other)}, + (Scalar::Rational{..}, Scalar::Float{..}) => {to_float(self) - other}, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {wrap_rational!(va.clone()-vb.clone())}, + } + } +} + +impl SubAssign for Scalar where { + fn sub_assign(&mut self, other: Self) { + match (&mut *self, &other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {*va -= vb.clone()}, + (Scalar::Float{..}, Scalar::Rational{..}) => {*self -= to_float(other)}, + (Scalar::Rational{..}, Scalar::Float{..}) => {*self = to_float(self.clone()) - other }, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {*va -= vb.clone()}, + } + } +} + +impl Mul for Scalar { + type Output = Self; + + fn mul(self, other: Self) -> Self::Output { + match (&self, &other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {wrap_float!(va.clone()*vb.clone())}, + (Scalar::Float{..}, Scalar::Rational{..}) => {self * to_float(other)}, + (Scalar::Rational{..}, Scalar::Float{..}) => {to_float(self) * other}, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {wrap_rational!(va.clone()*vb.clone())}, + } + } +} + +impl MulAssign for Scalar where { + fn mul_assign(&mut self, other: Self) { + match (&mut *self, &other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {*va *= vb.clone()}, + (Scalar::Float{..}, Scalar::Rational{..}) => {*self *= to_float(other)}, + (Scalar::Rational{..}, Scalar::Float{..}) => {*self = to_float(self.clone()) * other }, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {*va *= vb.clone()}, + } + } +} + +impl Div for Scalar { + type Output = Self; + + fn div(self, other: Self) -> Self::Output { + match (&self, &other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {wrap_float!(va.clone()/vb.clone())}, + (Scalar::Float{..}, Scalar::Rational{..}) => {self / to_float(other)}, + (Scalar::Rational{..}, Scalar::Float{..}) => {to_float(self) / other}, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {wrap_rational!(va.clone()/vb.clone())}, + } + } +} + +impl DivAssign for Scalar where { + fn div_assign(&mut self, other: Self) { + match (&mut *self, &other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {*va /= vb.clone()}, + (Scalar::Float{..}, Scalar::Rational{..}) => {*self /= to_float(other)}, + (Scalar::Rational{..}, Scalar::Float{..}) => {*self = to_float(self.clone()) / other }, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {*va /= vb.clone()}, + } + } +} + +impl Rem for Scalar { + type Output = Self; + + fn rem(self, other: Scalar) -> Self::Output { + match (&self, &other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {wrap_float!(va.clone()%vb.clone())}, + (Scalar::Float{..}, Scalar::Rational{..}) => {self % to_float(other)}, + (Scalar::Rational{..}, Scalar::Float{..}) => {to_float(self) % other}, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {wrap_rational!(va.clone()%vb.clone())}, + } + } +} + +impl PartialEq for Scalar { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => { va == vb }, + (Scalar::Float{..}, Scalar::Rational{..}) => {*self == to_float(other.clone())}, + (Scalar::Rational{..}, Scalar::Float{..}) => {to_float(self.clone()) == *other}, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => { va == vb }, + } + } +} + +impl PartialOrd for Scalar { + fn partial_cmp(&self, other: &Self) -> Option { + match (self, other) { + (Scalar::Float{v:va}, Scalar::Float{v:vb}) => {va.partial_cmp(vb)}, + (Scalar::Float{..}, Scalar::Rational{..}) => {(*self).partial_cmp(&to_float(other.clone()))}, + (Scalar::Rational{..}, Scalar::Float{..}) => {to_float(self.clone()).partial_cmp(other)}, + (Scalar::Rational{v:va}, Scalar::Rational{v:vb}) => {va.partial_cmp(vb)}, + } + } +} \ No newline at end of file diff --git a/src/quantity/rationalq.rs b/src/quantity/scalar/rationalbase.rs similarity index 69% rename from src/quantity/rationalq.rs rename to src/quantity/scalar/rationalbase.rs index bc1a130..df9d102 100644 --- a/src/quantity/rationalq.rs +++ b/src/quantity/scalar/rationalbase.rs @@ -10,20 +10,18 @@ use std::ops::{ }; use std::cmp::Ordering; - -use crate::quantity::QuantBase; -use crate::quantity::RationalBase; +use super::ScalarBase; macro_rules! cant_do { ( $x:ident ) => { - fn $x(&self) -> Option { None } + fn $x(&self) -> Option { None } } } #[derive(Debug)] #[derive(Clone)] -pub struct RationalQ where { +pub struct RationalBase where { pub val: Rational } @@ -37,65 +35,22 @@ fn to_sign_string_exp(&self, radix: i32, num_digits: Option) -> (bool, St } */ -impl ToString for RationalQ{ +impl ToString for RationalBase{ fn to_string(&self) -> String { return self.val.to_string(); } } -impl QuantBase for RationalQ { +impl ScalarBase for RationalBase { - fn fract(&self) -> Option { - Some(RationalQ{val: self.val.clone().fract_floor(Integer::new()).0}) - } - fn is_zero(&self) -> bool {self.val == Rational::from((0,1))} - fn is_negative(&self) -> bool { self.val.clone().signum() == -1 } - fn is_positive(&self) -> bool { self.val.clone().signum() == 1 } - - fn abs(&self) -> Option {Some(RationalQ{val: self.val.clone().abs()})} - fn floor(&self) -> Option {Some(RationalQ{val: self.val.clone().floor()})} - fn ceil(&self) -> Option {Some(RationalQ{val: self.val.clone().ceil()})} - fn round(&self) -> Option {Some(RationalQ{val: self.val.clone().round()})} - - cant_do!(sin); - cant_do!(cos); - cant_do!(tan); - cant_do!(asin); - cant_do!(acos); - cant_do!(atan); - - cant_do!(sinh); - cant_do!(cosh); - cant_do!(tanh); - cant_do!(asinh); - cant_do!(acosh); - cant_do!(atanh); - - cant_do!(exp); - cant_do!(ln); - cant_do!(log10); - cant_do!(log2); - - fn log(&self, _base: RationalQ) -> Option { None } - fn pow(&self, _base: RationalQ) -> Option { None } - -} - -impl RationalBase for RationalQ { - fn from_frac(top: i64, bot: i64) -> RationalQ { - return RationalQ { - val: Rational::from((top, bot)) - } - } - - fn from_f64(f: f64) -> Option { + fn from_f64(f: f64) -> Option { let v = Rational::from_f64(f); if v.is_none() { return None } - return Some(RationalQ{ val: v.unwrap() }); + return Some(RationalBase{ val: v.unwrap() }); } - fn from_string(s: &str) -> Option { + fn from_string(s: &str) -> Option { // Scientific notation let mut sci = s.split("e"); let num = sci.next().unwrap(); @@ -145,15 +100,50 @@ impl RationalBase for RationalQ { Err(_) => return None }; - return Some(RationalQ{val: r}); + return Some(RationalBase{val: r}); } + + fn fract(&self) -> Option { + Some(RationalBase{val: self.val.clone().fract_floor(Integer::new()).0}) + } + + fn is_zero(&self) -> bool {self.val == Rational::from((0,1))} + fn is_negative(&self) -> bool { self.val.clone().signum() == -1 } + fn is_positive(&self) -> bool { self.val.clone().signum() == 1 } + + fn abs(&self) -> Option {Some(RationalBase{val: self.val.clone().abs()})} + fn floor(&self) -> Option {Some(RationalBase{val: self.val.clone().floor()})} + fn ceil(&self) -> Option {Some(RationalBase{val: self.val.clone().ceil()})} + fn round(&self) -> Option {Some(RationalBase{val: self.val.clone().round()})} + + cant_do!(sin); + cant_do!(cos); + cant_do!(tan); + cant_do!(asin); + cant_do!(acos); + cant_do!(atan); + + cant_do!(sinh); + cant_do!(cosh); + cant_do!(tanh); + cant_do!(asinh); + cant_do!(acosh); + cant_do!(atanh); + + cant_do!(exp); + cant_do!(ln); + cant_do!(log10); + cant_do!(log2); + + fn log(&self, _base: RationalBase) -> Option { None } + fn pow(&self, _base: RationalBase) -> Option { None } + } - -impl Add for RationalQ where { +impl Add for RationalBase where { type Output = Self; fn add(self, other: Self) -> Self::Output { @@ -163,13 +153,13 @@ impl Add for RationalQ where { } } -impl AddAssign for RationalQ where { +impl AddAssign for RationalBase where { fn add_assign(&mut self, other: Self) { self.val += other.val; } } -impl Sub for RationalQ { +impl Sub for RationalBase { type Output = Self; fn sub(self, other: Self) -> Self::Output { @@ -179,13 +169,13 @@ impl Sub for RationalQ { } } -impl SubAssign for RationalQ where { +impl SubAssign for RationalBase where { fn sub_assign(&mut self, other: Self) { self.val -= other.val; } } -impl Mul for RationalQ { +impl Mul for RationalBase { type Output = Self; fn mul(self, other: Self) -> Self::Output { @@ -195,13 +185,13 @@ impl Mul for RationalQ { } } -impl MulAssign for RationalQ where { +impl MulAssign for RationalBase where { fn mul_assign(&mut self, other: Self) { self.val *= other.val; } } -impl Div for RationalQ { +impl Div for RationalBase { type Output = Self; fn div(self, other: Self) -> Self::Output { @@ -211,13 +201,13 @@ impl Div for RationalQ { } } -impl DivAssign for RationalQ where { +impl DivAssign for RationalBase where { fn div_assign(&mut self, other: Self) { self.val /= other.val; } } -impl Neg for RationalQ where { +impl Neg for RationalBase where { type Output = Self; fn neg(self) -> Self::Output { @@ -227,16 +217,16 @@ impl Neg for RationalQ where { } } -impl Rem for RationalQ { +impl Rem for RationalBase { type Output = Self; - fn rem(self, modulus: RationalQ) -> Self::Output { + fn rem(self, modulus: RationalBase) -> Self::Output { if { *self.val.denom() != 1 || *modulus.val.denom() != 1 } { panic!() } - RationalQ{ + RationalBase{ val : Rational::from(( self.val.numer() % modulus.val.numer(), 1 @@ -245,13 +235,13 @@ impl Rem for RationalQ { } } -impl PartialEq for RationalQ { +impl PartialEq for RationalBase { fn eq(&self, other: &Self) -> bool { self.val == other.val } } -impl PartialOrd for RationalQ { +impl PartialOrd for RationalBase { fn partial_cmp(&self, other: &Self) -> Option { self.val.partial_cmp(&other.val) } diff --git a/src/tokens/operator.rs b/src/tokens/operator.rs index 13d2de8..e6290b5 100644 --- a/src/tokens/operator.rs +++ b/src/tokens/operator.rs @@ -284,7 +284,7 @@ impl Operator { Token::Operator( Operator::Power, - VecDeque::from(vec!(a, Token::Number(Quantity::new_rational(1,2)))) + VecDeque::from(vec!(a, Token::Number(Quantity::new_rational(0.5).unwrap()))) ) }, @@ -328,12 +328,12 @@ impl Operator{ if let Token::Number(v) = args { if v.is_zero() { return Err(()); } - return Ok(Token::Number(Quantity::new_rational(1,1)/v)); + return Ok(Token::Number(Quantity::new_rational(1f64).unwrap()/v)); } else { panic!(); } }, Operator::Add => { - let mut sum = Quantity::new_rational(0,1); + let mut sum = Quantity::new_rational(0f64).unwrap(); for i in args.iter() { let j = i.as_number(); if let Token::Number(v) = j { @@ -346,7 +346,7 @@ impl Operator{ }, Operator::Multiply => { - let mut prod = Quantity::new_rational(1,1); + let mut prod = Quantity::new_rational(1f64).unwrap(); for i in args.iter() { let j = i.as_number(); if let Token::Number(v) = j { @@ -366,9 +366,9 @@ impl Operator{ if let Token::Number(va) = a { if let Token::Number(vb) = b { - if vb <= Quantity::new_rational(1,1) { return Err(()); } - if va.fract() != Quantity::new_rational(0,1) { return Err(()); } - if vb.fract() != Quantity::new_rational(0,1) { return Err(()); } + if vb <= Quantity::new_rational(1f64).unwrap() { return Err(()); } + if va.fract() != Quantity::new_rational(0f64).unwrap() { return Err(()); } + if vb.fract() != Quantity::new_rational(0f64).unwrap() { return Err(()); } return Ok(Token::Number(va%vb)); } else { panic!(); } @@ -395,13 +395,13 @@ impl Operator{ if let Token::Number(v) = args { if !v.fract().is_zero() { return Err(()); } - if v > Quantity::new_rational(50_000, 1) { return Err(()); } + if v > Quantity::new_rational(50_000f64).unwrap() { return Err(()); } - let mut prod = Quantity::new_rational(1, 1); + let mut prod = Quantity::new_rational(1f64).unwrap(); let mut u = v.clone(); - while u > Quantity::new_rational(0, 1) { + while u > Quantity::new_rational(0f64).unwrap() { prod *= u.clone(); - u = u - Quantity::new_rational(1, 1); + u = u - Quantity::new_rational(1f64).unwrap(); } return Ok(Token::Number(prod));