From 0ca77051224cb4363a9825ed99cfcbcf12801572 Mon Sep 17 00:00:00 2001 From: Mark Date: Tue, 11 Apr 2023 08:56:39 -0700 Subject: [PATCH] Cleanup --- src/quantity/scalar/floatbase.rs | 21 +- src/quantity/scalar/mod.rs | 390 +-------------------------- src/quantity/scalar/rationalbase.rs | 5 + src/quantity/scalar/scalar.rs | 397 ++++++++++++++++++++++++++++ 4 files changed, 419 insertions(+), 394 deletions(-) create mode 100644 src/quantity/scalar/scalar.rs diff --git a/src/quantity/scalar/floatbase.rs b/src/quantity/scalar/floatbase.rs index c588dc5..781a90c 100644 --- a/src/quantity/scalar/floatbase.rs +++ b/src/quantity/scalar/floatbase.rs @@ -17,15 +17,6 @@ use super::ScalarBase; use super::PRINT_LEN; use super::FLOAT_PRECISION; - -macro_rules! foward { - ( $x:ident ) => { - fn $x(&self) -> Option { - Some(FloatBase{ val: self.val.clone().$x()}) - } - } -} - #[derive(Debug)] #[derive(Clone)] pub struct FloatBase where { @@ -99,6 +90,14 @@ impl ToString for FloatBase { } +macro_rules! foward { + ( $x:ident ) => { + fn $x(&self) -> Option { + Some(FloatBase{ val: self.val.clone().$x()}) + } + } +} + impl ScalarBase for FloatBase { fn from_f64(f: f64) -> Option { @@ -127,6 +126,10 @@ impl ScalarBase for FloatBase { fn is_negative(&self) -> bool { self.val.is_sign_negative() } fn is_positive(&self) -> bool { self.val.is_sign_positive() } + fn is_int(&self) -> bool { + self.fract() == FloatBase::from_f64(0f64) + } + foward!(abs); foward!(floor); foward!(ceil); diff --git a/src/quantity/scalar/mod.rs b/src/quantity/scalar/mod.rs index 22b7e9a..65a4722 100644 --- a/src/quantity/scalar/mod.rs +++ b/src/quantity/scalar/mod.rs @@ -1,390 +1,10 @@ -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_one(&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; +pub(in self) mod rationalbase; +pub(in self) 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_one(&self) -> bool { - match self { - Scalar::Rational{v} => v.is_one(), - Scalar::Float{v} => v.is_one(), - } - } - - 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 +mod scalar; +pub use self::scalar::Scalar; +pub use self::scalar::ScalarBase; \ No newline at end of file diff --git a/src/quantity/scalar/rationalbase.rs b/src/quantity/scalar/rationalbase.rs index 7c41107..3170f67 100644 --- a/src/quantity/scalar/rationalbase.rs +++ b/src/quantity/scalar/rationalbase.rs @@ -1,5 +1,6 @@ use rug::Rational; use rug::Integer; +use rug::ops::Pow; use std::ops::{ Add, Sub, Mul, Div, @@ -109,6 +110,10 @@ impl ScalarBase for RationalBase { Some(RationalBase{val: self.val.clone().fract_floor(Integer::new()).0}) } + fn is_int(&self) -> bool { + self.fract() == RationalBase::from_f64(0f64) + } + fn is_zero(&self) -> bool {self.val == Rational::from((0,1))} fn is_one(&self) -> bool {self.val == Rational::from((1,1))} fn is_negative(&self) -> bool { self.val.clone().signum() == -1 } diff --git a/src/quantity/scalar/scalar.rs b/src/quantity/scalar/scalar.rs new file mode 100644 index 0000000..05d8672 --- /dev/null +++ b/src/quantity/scalar/scalar.rs @@ -0,0 +1,397 @@ +use std::ops::{ + Add, Sub, Mul, Div, + Neg, Rem, + + AddAssign, SubAssign, + MulAssign, DivAssign +}; +use std::cmp::Ordering; + +use super::floatbase::FloatBase as FloatBase; +use super::rationalbase::RationalBase; + + +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_one(&self) -> bool; + fn is_int(&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; +} + + + + +#[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())) + } +} + + +// 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_one(&self) -> bool { + match self { + Scalar::Rational{v} => v.is_one(), + Scalar::Float{v} => v.is_one(), + } + } + + 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(), + } + } + + pub fn is_nan(&self) -> bool { + match self { + Scalar::Float {v} => {v.val.is_nan()}, + Scalar::Rational {..} => {panic!()} + } + } + + pub fn is_rational(&self) -> bool { + match self { + Scalar::Float { .. } => false, + Scalar::Rational {..} => true + } + } + + pub fn is_int(&self) -> bool { + match self { + Scalar::Rational{v} => v.is_int(), + Scalar::Float{v} => v.is_int(), + } + } + + 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