Added conversion between prefixed units

pull/2/head
Mark 2023-04-13 09:01:18 -07:00
parent 14ab0bd1d8
commit 84d2d68aa1
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
2 changed files with 110 additions and 23 deletions

View File

@ -93,7 +93,6 @@ impl Quantity {
pub fn set_unit(&mut self, u: Unit) { self.u = u; }
pub fn convert_to(self, other: Quantity) -> Option<Quantity> {
let fa = self.u.to_base_factor();
let fb = other.u.to_base_factor();
@ -185,8 +184,13 @@ impl Add for Quantity {
fn add(self, other: Self) -> Self::Output {
if self.u != other.u { panic!() }
let mut o = other;
if !o.u.prefixes_match(&self.u) {
o = o.convert_to(self.clone()).unwrap();
}
Quantity {
v: self.v + other.v,
v: self.v + o.v,
u: self.u
}
}
@ -195,7 +199,13 @@ impl Add for Quantity {
impl AddAssign for Quantity where {
fn add_assign(&mut self, other: Self) {
if self.u != other.u { panic!() }
self.v += other.v
let mut o = other;
if !o.u.prefixes_match(&self.u) {
o = o.convert_to(self.clone()).unwrap();
}
self.v += o.v
}
}
@ -205,8 +215,13 @@ impl Sub for Quantity {
fn sub(self, other: Self) -> Self::Output {
if self.u != other.u { panic!() }
let mut o = other;
if !o.u.prefixes_match(&self.u) {
o = o.convert_to(self.clone()).unwrap();
}
Quantity {
v: self.v - other.v,
v: self.v - o.v,
u: self.u
}
}
@ -215,7 +230,13 @@ impl Sub for Quantity {
impl SubAssign for Quantity where {
fn sub_assign(&mut self, other: Self) {
if self.u != other.u { panic!() }
self.v -= other.v
let mut o = other;
if !o.u.prefixes_match(&self.u) {
o = o.convert_to(self.clone()).unwrap();
}
self.v -= o.v
}
}
@ -223,17 +244,22 @@ impl Mul for Quantity {
type Output = Self;
fn mul(self, other: Self) -> Self::Output {
let f = self.u.match_prefix_factor(&other.u);
Quantity {
v: self.v * other.v,
u: self.u * other.u
v: self.v * other.v * f.v,
u: self.u * other.u * f.u,
}
}
}
impl MulAssign for Quantity where {
fn mul_assign(&mut self, other: Self) {
self.v *= other.v;
self.u *= other.u;
let f = self.u.match_prefix_factor(&other.u);
self.v *= other.v * f.v;
self.u *= other.u * f.u;
}
}

View File

@ -1,5 +1,5 @@
use std::collections::HashMap;
use std::f32::consts::E;
use std::hash::{Hash, Hasher};
use std::ops::{
Mul, Div,
MulAssign, DivAssign
@ -142,15 +142,27 @@ impl ToString for Prefix {
}
#[derive(Hash)]
#[derive(Debug)]
#[derive(Copy, Clone)]
#[derive(Eq, PartialEq)]
pub struct FreeUnit {
u: UnitBase,
p: Prefix
}
impl Hash for FreeUnit {
fn hash<H: Hasher>(&self, state: &mut H) {
self.u.hash(state);
}
}
impl Eq for FreeUnit {}
impl PartialEq for FreeUnit {
fn eq(&self, other: &Self) -> bool {
self.u.eq(&other.u)
}
}
macro_rules! quick_base_factor {
(float, $u:expr, $s:expr, $( ($x:expr, $p:expr) ),* ) => {
Some(Quantity {
@ -180,19 +192,17 @@ macro_rules! quick_base_factor {
impl FreeUnit {
pub fn from_base(u: UnitBase) -> FreeUnit {
return FreeUnit {
u,
p: Prefix::None
}
return FreeUnit { u, p: Prefix::None }
}
pub fn from_base_prefix(u: UnitBase, p: Prefix) -> FreeUnit {
return FreeUnit { u, p }
pub fn from_base_prefix(u: UnitBase, p: Prefix) -> FreeUnit { FreeUnit {u, p} }
pub fn set_prefix(&mut self, p: Prefix) { self.p = p; }
pub fn get_prefix(&self) -> Prefix { self.p }
pub fn same_with_prefix(&self, other: &FreeUnit) -> bool {
self.u.eq(&other.u) && self.p.eq(&other.p)
}
pub fn set_prefix(&mut self, p: Prefix) {
self.p = p;
}
pub fn to_base_factor(&self) -> Quantity {
let q = match self.u {
@ -360,6 +370,46 @@ impl Unit {
return n;
}
pub fn prefixes_match(&self, other: &Unit) -> bool {
let v = self.get_val();
for (u, _) in other.get_val() {
let k = v.get_key_value(u);
if k.is_some() {
let k = k.unwrap().0;
if !u.same_with_prefix(k) { return false; }
}
}
return true;
}
pub fn match_prefix_factor(&self, other: &Unit) -> Quantity {
let mut f = Quantity::new_rational(1f64).unwrap();
let v = self.get_val();
for (ou, op) in other.get_val() {
let k = v.get_key_value(ou);
if k.is_some() {
let (su, _) = k.unwrap();
// Conversion factor ou -> basic
let mut p = ou.p.to_ratio();
p.insert_unit(FreeUnit::from_base(ou.u), Scalar::new_rational(1f64).unwrap());
p.insert_unit(FreeUnit::from_base_prefix(ou.u, ou.p), Scalar::new_rational(-1f64).unwrap());
// Conversion factor su -> basic
let mut q = su.p.to_ratio();
q.insert_unit(FreeUnit::from_base(su.u), Scalar::new_rational(1f64).unwrap());
q.insert_unit(FreeUnit::from_base_prefix(su.u, su.p), Scalar::new_rational(-1f64).unwrap());
f = f * (p / q).pow(Quantity::from_scalar(op.clone()));
}
}
return f;
}
pub fn unitless(&self) -> bool { self.get_val().len() == 0 }
pub fn insert(&mut self, u: FreeUnit, p: Scalar) {
@ -419,8 +469,19 @@ impl Unit {
if b.is_none() {
if s == "kg" {
let mut u = Unit::new();
let mut b = FreeUnit::from_base(UnitBase::Gram);
b.set_prefix(Prefix::Kilo);
let b = FreeUnit::from_base_prefix(UnitBase::Gram, Prefix::Kilo);
u.insert(b, Scalar::new_rational(1f64).unwrap());
let mut q = Quantity::new_rational(1f64).unwrap();
q.set_unit(u);
return Some(q);
}
if s == "km" {
let mut u = Unit::new();
let b = FreeUnit::from_base_prefix(UnitBase::Meter, Prefix::Kilo);
u.insert(b, Scalar::new_rational(1f64).unwrap());