From 5b8dd2f703937f208e41604200e2d23ba1a1fa6f Mon Sep 17 00:00:00 2001 From: Mark Date: Sat, 8 Apr 2023 16:47:47 -0700 Subject: [PATCH] Added basic units (incomplete) --- src/parser/mod.rs | 15 ++- src/quantity/floatq.rs | 23 ++-- src/quantity/mod.rs | 53 ++++---- src/quantity/quantity.rs | 268 +++++++++++++++++++++++++++++--------- src/quantity/rationalq.rs | 64 ++++----- src/quantity/unit.rs | 112 ++++++++++++++++ src/tokens/function.rs | 1 - src/tokens/operator.rs | 1 - 8 files changed, 396 insertions(+), 141 deletions(-) create mode 100644 src/quantity/unit.rs diff --git a/src/parser/mod.rs b/src/parser/mod.rs index dfc777f..783653c 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12,7 +12,7 @@ use crate::parser::groupify::groupify; use crate::parser::treeify::treeify; use crate::parser::find_subs::find_subs; -use crate::quantity::Quantity; +use crate::quantity::{Quantity, BaseUnit}; use crate::tokens::Token; @@ -96,6 +96,19 @@ impl PreToken { "e" => { Token::Constant(Quantity::new_float_from_string("2.718281828459045235360287471352662497757247093699959574966967627724076630353547594571382178525166427").unwrap(), String::from("e")) }, "phi"|"φ" => { Token::Constant(Quantity::new_float_from_string("1.618033988749894848204586834365638117720309179805762862135448622705260462818902449707207204189391137").unwrap(), String::from("φ")) }, + // Units + "m" => { + let mut u = Quantity::new_rational(1, 1); + u.add_unit(BaseUnit::Meter, 1f64); + Token::Number(u) + }, + + "s" => { + let mut u = Quantity::new_rational(1, 1); + u.add_unit(BaseUnit::Second, 1f64); + Token::Number(u) + } + _ => { return Err((l, ParserError::Undefined(s))); } }); } diff --git a/src/quantity/floatq.rs b/src/quantity/floatq.rs index d50796d..a2d275e 100644 --- a/src/quantity/floatq.rs +++ b/src/quantity/floatq.rs @@ -13,8 +13,6 @@ 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 crate::quantity::PRINT_LEN; @@ -24,8 +22,8 @@ use super::FLOAT_PRECISION; macro_rules! foward { ( $x:ident ) => { - fn $x(&self) -> Quantity { - wrap_float!(FloatQ{ val: self.val.clone().$x()}) + fn $x(&self) -> Option { + Some(FloatQ{ val: self.val.clone().$x()}) } } } @@ -135,17 +133,12 @@ impl QuantBase for FloatQ { foward!(log10); foward!(log2); - fn log(&self, base: Quantity) -> Quantity { - wrap_float!(FloatQ{ val: self.val.clone().log10() }) / - Quantity::float_from_rat(&base).log10() + fn log(&self, base: FloatQ) -> Option { + Some(FloatQ{ 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!(FloatQ{ val: self.val.clone().pow(v.val)}) - } - + fn pow(&self, base: FloatQ) -> Option { + Some(FloatQ{ val: self.val.clone().pow(base.val)}) } } @@ -242,8 +235,8 @@ impl Rem for FloatQ { fn rem(self, modulus: FloatQ) -> Self::Output { if { - (!self.fract().is_zero()) || - (!modulus.fract().is_zero()) + (!self.fract().unwrap().is_zero()) || + (!modulus.fract().unwrap().is_zero()) } { panic!() } FloatQ{val : self.val.fract() % modulus.val.fract()} diff --git a/src/quantity/mod.rs b/src/quantity/mod.rs index c018aff..18b7aa2 100644 --- a/src/quantity/mod.rs +++ b/src/quantity/mod.rs @@ -25,6 +25,9 @@ cross-compilation to other systems. RUG does not work on all systems. */ pub mod quantity; +mod unit; +pub use crate::quantity::unit::Unit; +pub use crate::quantity::unit::BaseUnit; cfg_if::cfg_if! { if #[cfg(target_family = "unix")] { @@ -36,11 +39,11 @@ cfg_if::cfg_if! { } macro_rules! wrap_rational { - ( $x:expr ) => { Quantity::Rational{v: $x} } + ( $x:expr, $y:expr ) => { Quantity::Rational{v: $x, u: $y} } } macro_rules! wrap_float { - ( $x:expr ) => { Quantity::Float{v: $x} } + ( $x:expr, $y:expr ) => { Quantity::Float{v: $x, u: $y} } } pub use crate::quantity::quantity::Quantity; @@ -72,31 +75,31 @@ pub trait QuantBase: Neg + Rem + PartialEq + PartialOrd { - fn fract(&self) -> Quantity; + fn fract(&self) -> Option; fn is_zero(&self) -> bool; fn is_negative(&self) -> bool; fn is_positive(&self) -> bool; - fn exp(&self) -> Quantity; - fn abs(&self) -> Quantity; - fn floor(&self) -> Quantity; - fn ceil(&self) -> Quantity; - fn round(&self) -> Quantity; - fn sin(&self) -> Quantity; - fn cos(&self) -> Quantity; - fn tan(&self) -> Quantity; - fn asin(&self) -> Quantity; - fn acos(&self) -> Quantity; - fn atan(&self) -> Quantity; - fn sinh(&self) -> Quantity; - fn cosh(&self) -> Quantity; - fn tanh(&self) -> Quantity; - fn asinh(&self) -> Quantity; - fn acosh(&self) -> Quantity; - fn atanh(&self) -> Quantity; - fn ln(&self) -> Quantity; - fn log10(&self) -> Quantity; - fn log2(&self) -> Quantity; - fn log(&self, base: Quantity) -> Quantity; - fn pow(&self, exp: Quantity) -> Quantity; + 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 9a6d2b3..70b1e99 100644 --- a/src/quantity/quantity.rs +++ b/src/quantity/quantity.rs @@ -14,6 +14,8 @@ 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")] { @@ -23,8 +25,8 @@ cfg_if::cfg_if! { #[derive(Debug)] #[derive(Clone)] pub enum Quantity { - Rational{ v: RationalQ }, - Float{ v: FloatQ } + Rational{ v: RationalQ, u: Unit }, + Float{ v: FloatQ, u: Unit } } } else { use crate::quantity::f64q::F64Q; @@ -32,8 +34,8 @@ cfg_if::cfg_if! { #[derive(Debug)] #[derive(Clone)] pub enum Quantity { - Rational{ v: F64Q }, - Float{ v: F64Q } + Rational{ v: F64Q, u: Unit }, + Float{ v: F64Q, u: Unit } } } } @@ -44,31 +46,44 @@ 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)); + 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()) + 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())); + 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())) + 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 } => wrap_float!( + Quantity::Rational { v, u } => wrap_float!( FloatQ::from(v.val.numer()).unwrap() / - FloatQ::from(v.val.denom()).unwrap() + FloatQ::from(v.val.denom()).unwrap(), + u.clone() ) } } @@ -102,61 +117,93 @@ impl Quantity { } } - - - - pub fn is_nan(&self) -> bool { match self { - Quantity::Float { v } => {v.val.is_nan()}, + 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)} + } + } } impl ToString for Quantity { fn to_string(&self) -> String { + let mut n: String; + let u: &Unit; match self { - Quantity::Rational{v} => v.to_string(), - Quantity::Float{v} => v.to_string(), - } + 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; + }, + }; + + //n.push(' '); + //n.push_str(&u.to_string()); + n } } macro_rules! quant_foward { ( $x:ident ) => { - fn $x(&self) -> Quantity { + pub fn $x(&self) -> Quantity { match self { - Quantity::Rational{v} => v.$x(), - Quantity::Float{v} => v.$x(), + 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()) + }, } } } } -impl QuantBase for Quantity { +impl Quantity { - fn is_zero(&self) -> bool { + pub fn is_zero(&self) -> bool { match self { - Quantity::Rational{v} => v.is_zero(), - Quantity::Float{v} => v.is_zero(), + Quantity::Rational{v, .. } => v.is_zero(), + Quantity::Float{v, .. } => v.is_zero(), } } - fn is_negative(&self) -> bool { + pub fn is_negative(&self) -> bool { match self { - Quantity::Rational{v} => v.is_negative(), - Quantity::Float{v} => v.is_negative(), + Quantity::Rational{v, .. } => v.is_negative(), + Quantity::Float{v, .. } => v.is_negative(), } } - fn is_positive(&self) -> bool { + pub fn is_positive(&self) -> bool { match self { - Quantity::Rational{v} => v.is_positive(), - Quantity::Float{v} => v.is_positive(), + 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(), } } @@ -182,16 +229,55 @@ impl QuantBase for Quantity { quant_foward!(log10); quant_foward!(log2); - fn log(&self, base: Quantity) -> Quantity { + pub fn log(&self, base: Quantity) -> Quantity { + + if !self.unitless() { panic!() } + match self { - Quantity::Rational{v} => v.log(base), - Quantity::Float{v} => v.log(base), + 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) + }, } } - fn pow(&self, base: Quantity) -> Quantity { + pub fn pow(&self, base: Quantity) -> Quantity { match self { - Quantity::Rational{v} => v.pow(base), - Quantity::Float{v} => v.pow(base), + 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) + + }, } } } @@ -203,8 +289,8 @@ impl Neg for Quantity where { fn neg(self) -> Self::Output { match self { - Quantity::Float { v } => {wrap_float!(-v)}, - Quantity::Rational { v } => {wrap_rational!(-v)}, + Quantity::Float { v, u } => {wrap_float!(-v, u)}, + Quantity::Rational { v, u } => {wrap_rational!(-v, u)}, } } } @@ -214,10 +300,16 @@ impl Add for Quantity { fn add(self, other: Self) -> Self::Output { match (&self, &other) { - (Quantity::Float{v:a}, Quantity::Float{v:b}) => {wrap_float!(a.clone()+b.clone())}, + (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:a}, Quantity::Rational{v:b}) => {wrap_rational!(a.clone()+b.clone())}, + (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { + if ua != ub { panic!() } + wrap_rational!(va.clone()+vb.clone(), ua.clone()) + }, } } } @@ -225,10 +317,16 @@ impl Add for Quantity { impl AddAssign for Quantity where { fn add_assign(&mut self, other: Self) { match (&mut *self, &other) { - (Quantity::Float{v: a}, Quantity::Float{v: ref b}) => {*a += b.clone()}, + (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:a}, Quantity::Rational{v:b}) => {*a += b.clone()}, + (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { + if ua != ub { panic!() } + *va += vb.clone() + }, } } } @@ -238,10 +336,16 @@ impl Sub for Quantity { fn sub(self, other: Self) -> Self::Output { match (&self, &other) { - (Quantity::Float{v:a}, Quantity::Float{v:b}) => {wrap_float!(a.clone()-b.clone())}, + (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:a}, Quantity::Rational{v:b}) => {wrap_rational!(a.clone()-b.clone())}, + (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { + if ua != ub { panic!() } + wrap_rational!(va.clone()-vb.clone(), ua.clone()) + }, } } } @@ -249,10 +353,16 @@ impl Sub for Quantity { impl SubAssign for Quantity where { fn sub_assign(&mut self, other: Self) { match (&mut *self, &other) { - (Quantity::Float{v: a}, Quantity::Float{v: ref b}) => {*a -= b.clone()}, + (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:a}, Quantity::Rational{v:b}) => {*a -= b.clone()}, + (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { + if ua != ub { panic!() } + *va -= vb.clone() + }, } } } @@ -262,10 +372,16 @@ impl Mul for Quantity { fn mul(self, other: Self) -> Self::Output { match (&self, &other) { - (Quantity::Float{v:a}, Quantity::Float{v:b}) => {wrap_float!(a.clone()*b.clone())}, + (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:a}, Quantity::Rational{v:b}) => {wrap_rational!(a.clone()*b.clone())}, + (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) + }, } } } @@ -273,10 +389,16 @@ impl Mul for Quantity { impl MulAssign for Quantity where { fn mul_assign(&mut self, other: Self) { match (&mut *self, &other) { - (Quantity::Float{v: a}, Quantity::Float{v:b}) => {*a *= b.clone()}, + (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:a}, Quantity::Rational{v:b}) => {*a *= b.clone()}, + (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { + *ua *= ub.clone(); + *va *= vb.clone() + }, } } } @@ -286,10 +408,16 @@ impl Div for Quantity { fn div(self, other: Self) -> Self::Output { match (&self, &other) { - (Quantity::Float{v:a}, Quantity::Float{v:b}) => {wrap_float!(a.clone()/b.clone())}, + (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:a}, Quantity::Rational{v:b}) => {wrap_rational!(a.clone()/b.clone())}, + (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) + }, } } } @@ -297,10 +425,16 @@ impl Div for Quantity { impl DivAssign for Quantity where { fn div_assign(&mut self, other: Self) { match (&mut *self, &other) { - (Quantity::Float{v: a}, Quantity::Float{v: ref b}) => {*a /= b.clone()}, + (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:a}, Quantity::Rational{v:b}) => {*a /= b.clone()}, + (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { + *ua /= ub.clone(); + *va /= vb.clone() + } } } } @@ -310,10 +444,16 @@ impl Rem for Quantity { fn rem(self, other: Quantity) -> Self::Output { match (&self, &other) { - (Quantity::Float{v:a}, Quantity::Float{v:b}) => {wrap_float!(a.clone()%b.clone())}, + (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:a}, Quantity::Rational{v:b}) => {wrap_rational!(a.clone()%b.clone())}, + (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { + if ua != ub { panic!() } + wrap_rational!(va.clone()%vb.clone(), ua.clone()) + }, } } } @@ -321,10 +461,10 @@ impl Rem for Quantity { impl PartialEq for Quantity { fn eq(&self, other: &Self) -> bool { match (self, other) { - (Quantity::Float{v:a}, Quantity::Float{v:b}) => {a == b}, + (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:a}, Quantity::Rational{v:b}) => {a == b}, + (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { if ua!=ub {false} else {va == vb} }, } } } @@ -332,10 +472,16 @@ impl PartialEq for Quantity { impl PartialOrd for Quantity { fn partial_cmp(&self, other: &Self) -> Option { match (self, other) { - (Quantity::Float{v:a}, Quantity::Float{v:b}) => {a.partial_cmp(b)}, + (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:a}, Quantity::Rational{v:b}) => {a.partial_cmp(b)}, + (Quantity::Rational{v:va,u:ua}, Quantity::Rational{v:vb,u:ub}) => { + if ua != ub { panic!() } + va.partial_cmp(vb) + }, } } } \ No newline at end of file diff --git a/src/quantity/rationalq.rs b/src/quantity/rationalq.rs index 7016f20..bc1a130 100644 --- a/src/quantity/rationalq.rs +++ b/src/quantity/rationalq.rs @@ -11,17 +11,13 @@ use std::ops::{ use std::cmp::Ordering; -use crate::quantity::wrap_rational; -use crate::quantity::Quantity; use crate::quantity::QuantBase; use crate::quantity::RationalBase; -macro_rules! float_foward { +macro_rules! cant_do { ( $x:ident ) => { - fn $x(&self) -> Quantity { - Quantity::float_from_rat(&wrap_rational!(self.clone())).$x() - } + fn $x(&self) -> Option { None } } } @@ -43,52 +39,46 @@ fn to_sign_string_exp(&self, radix: i32, num_digits: Option) -> (bool, St impl ToString for RationalQ{ fn to_string(&self) -> String { - let v = Quantity::float_from_rat(&wrap_rational!(self.clone())); - return v.to_string(); + return self.val.to_string(); } } impl QuantBase for RationalQ { - fn fract(&self) -> Quantity { - wrap_rational!(RationalQ{val: self.val.clone().fract_floor(Integer::new()).0}) + 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) -> Quantity {wrap_rational!(RationalQ{val: self.val.clone().abs()})} - fn floor(&self) -> Quantity {wrap_rational!(RationalQ{val: self.val.clone().floor()})} - fn ceil(&self) -> Quantity {wrap_rational!(RationalQ{val: self.val.clone().ceil()})} - fn round(&self) -> Quantity {wrap_rational!(RationalQ{val: self.val.clone().round()})} + 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()})} - float_foward!(sin); - float_foward!(cos); - float_foward!(tan); - float_foward!(asin); - float_foward!(acos); - float_foward!(atan); + cant_do!(sin); + cant_do!(cos); + cant_do!(tan); + cant_do!(asin); + cant_do!(acos); + cant_do!(atan); - float_foward!(sinh); - float_foward!(cosh); - float_foward!(tanh); - float_foward!(asinh); - float_foward!(acosh); - float_foward!(atanh); + cant_do!(sinh); + cant_do!(cosh); + cant_do!(tanh); + cant_do!(asinh); + cant_do!(acosh); + cant_do!(atanh); - float_foward!(exp); - float_foward!(ln); - float_foward!(log10); - float_foward!(log2); + cant_do!(exp); + cant_do!(ln); + cant_do!(log10); + cant_do!(log2); - fn log(&self, base: Quantity) -> Quantity { - Quantity::float_from_rat(&wrap_rational!(self.clone())).log10() / base.log10() - } - - fn pow(&self, base: Quantity) -> Quantity { - Quantity::float_from_rat(&wrap_rational!(self.clone())).pow(base) - } + fn log(&self, _base: RationalQ) -> Option { None } + fn pow(&self, _base: RationalQ) -> Option { None } } diff --git a/src/quantity/unit.rs b/src/quantity/unit.rs new file mode 100644 index 0000000..28abd1e --- /dev/null +++ b/src/quantity/unit.rs @@ -0,0 +1,112 @@ +use std::{collections::HashMap, hash::Hash}; + + +use std::ops::{ + Mul, Div, + MulAssign, DivAssign +}; + +#[derive(Debug)] +#[derive(Hash)] +#[derive(Eq, PartialEq)] +#[derive(Copy, Clone)] +pub enum BaseUnit { + Second, + Meter, + Kilogram, + Ampere, + Kelvin, + Mole, + Candela +} + +#[derive(Debug)] +#[derive(Clone)] +pub struct Unit { + // Unit, power. + pub val: HashMap +} + + +impl ToString for Unit { + fn to_string(&self) -> String { + format!("{:?}", self) + } +} + + +impl Unit { + + pub fn new() -> Unit { + return Unit{ + val: HashMap::new() + } + } + + pub fn unitless(&self) -> bool { self.val.len() == 0 } + + pub fn insert(&mut self, u: BaseUnit, p: f64) { + match self.val.get_mut(&u) { + Some(i) => { + let n = *i + p; + + if n == 0f64 { + self.val.remove(&u); + } else { *i = n; } + }, + None => { self.val.insert(u, p); } + }; + } + + pub fn pow(&mut self, pwr: f64) { + for (_, p) in &mut self.val { + *p *= pwr; + } + } + +} + + +impl PartialEq for Unit { + fn eq(&self, other: &Self) -> bool { + for (u, p) in &other.val { + match self.val.get(u) { + Some(i) => { if i != p { return false; } }, + None => { return false; } + }; + } + return true; + } +} + +impl Mul for Unit { + type Output = Self; + + fn mul(self, other: Self) -> Self::Output { + let mut o = self.clone(); + for (u, p) in &other.val { o.insert(*u, *p); } + return o; + } +} + +impl MulAssign for Unit where { + fn mul_assign(&mut self, other: Self) { + for (u, p) in &other.val { self.insert(*u, *p); } + } +} + +impl Div for Unit { + type Output = Self; + + fn div(self, other: Self) -> Self::Output { + let mut o = self.clone(); + for (u, p) in &other.val { o.insert(*u, -*p); } + return o; + } +} + +impl DivAssign for Unit where { + fn div_assign(&mut self, other: Self) { + for (u, p) in &other.val { self.insert(*u, -*p); } + } +} diff --git a/src/tokens/function.rs b/src/tokens/function.rs index 28a1bd9..35720c6 100644 --- a/src/tokens/function.rs +++ b/src/tokens/function.rs @@ -2,7 +2,6 @@ use std::collections::VecDeque; use crate::tokens::Token; use crate::tokens::Operator; -use crate::quantity::QuantBase; #[derive(Debug)] #[derive(Copy, Clone)] diff --git a/src/tokens/operator.rs b/src/tokens/operator.rs index 700bbe2..13d2de8 100644 --- a/src/tokens/operator.rs +++ b/src/tokens/operator.rs @@ -4,7 +4,6 @@ use std::cmp::Ordering; use crate::tokens::Token; use crate::tokens::Function; use crate::quantity::Quantity; -use crate::quantity::QuantBase; /// Operator types, in order of increasing priority. #[derive(Debug)]