mirror of https://github.com/rm-dr/daisy
Fixed unit conversion
parent
7560b7a931
commit
5de314e11c
|
@ -94,14 +94,12 @@ impl Quantity {
|
|||
|
||||
|
||||
pub fn convert_to(self, other: Quantity) -> Option<Quantity> {
|
||||
if !self.unit.compatible_with(&other.unit) { return None; }
|
||||
|
||||
let fa = self.unit.to_base_factor();
|
||||
let fb = other.unit.to_base_factor();
|
||||
let r = self * fa / fb;
|
||||
|
||||
// If this didn't work, units are incompatible
|
||||
if r.unit != other.unit { return None; };
|
||||
|
||||
return Some(r);
|
||||
return Some(self * fa / fb)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,6 +165,33 @@ impl Quantity {
|
|||
}
|
||||
|
||||
|
||||
impl Quantity {
|
||||
pub fn mul_no_convert(self, other: Self) -> Self {
|
||||
Quantity {
|
||||
scalar: self.scalar * other.scalar,
|
||||
unit: self.unit * other.unit
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mul_assign_no_convert(&mut self, other: Self) {
|
||||
self.scalar *= other.scalar;
|
||||
self.unit *= other.unit;
|
||||
}
|
||||
|
||||
pub fn div_no_convert(self, other: Self) -> Self {
|
||||
Quantity {
|
||||
scalar: self.scalar / other.scalar,
|
||||
unit: self.unit / other.unit
|
||||
}
|
||||
}
|
||||
|
||||
pub fn div_assign_no_convert(&mut self, other: Self) {
|
||||
self.scalar *= other.scalar;
|
||||
self.unit *= other.unit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl Neg for Quantity where {
|
||||
type Output = Self;
|
||||
|
||||
|
@ -182,10 +207,10 @@ impl Add for Quantity {
|
|||
type Output = Self;
|
||||
|
||||
fn add(self, other: Self) -> Self::Output {
|
||||
if self.unit != other.unit { panic!() }
|
||||
if !self.unit.compatible_with(&other.unit) { panic!() }
|
||||
|
||||
let mut o = other;
|
||||
if !o.unit.prefixes_match(&self.unit) {
|
||||
if self.unit != o.unit {
|
||||
o = o.convert_to(self.clone()).unwrap();
|
||||
}
|
||||
|
||||
|
@ -198,10 +223,10 @@ impl Add for Quantity {
|
|||
|
||||
impl AddAssign for Quantity where {
|
||||
fn add_assign(&mut self, other: Self) {
|
||||
if self.unit != other.unit { panic!() }
|
||||
if !self.unit.compatible_with(&other.unit) { panic!() }
|
||||
|
||||
let mut o = other;
|
||||
if !o.unit.prefixes_match(&self.unit) {
|
||||
if self.unit != o.unit {
|
||||
o = o.convert_to(self.clone()).unwrap();
|
||||
}
|
||||
|
||||
|
@ -213,10 +238,10 @@ impl Sub for Quantity {
|
|||
type Output = Self;
|
||||
|
||||
fn sub(self, other: Self) -> Self::Output {
|
||||
if self.unit != other.unit { panic!() }
|
||||
if !self.unit.compatible_with(&other.unit) { panic!() }
|
||||
|
||||
let mut o = other;
|
||||
if !o.unit.prefixes_match(&self.unit) {
|
||||
if self.unit != o.unit {
|
||||
o = o.convert_to(self.clone()).unwrap();
|
||||
}
|
||||
|
||||
|
@ -229,10 +254,10 @@ impl Sub for Quantity {
|
|||
|
||||
impl SubAssign for Quantity where {
|
||||
fn sub_assign(&mut self, other: Self) {
|
||||
if self.unit != other.unit { panic!() }
|
||||
if !self.unit.compatible_with(&other.unit) { panic!() }
|
||||
|
||||
let mut o = other;
|
||||
if !o.unit.prefixes_match(&self.unit) {
|
||||
if self.unit != o.unit {
|
||||
o = o.convert_to(self.clone()).unwrap();
|
||||
}
|
||||
|
||||
|
@ -240,26 +265,38 @@ impl SubAssign for Quantity where {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
impl Mul for Quantity {
|
||||
type Output = Self;
|
||||
|
||||
fn mul(self, other: Self) -> Self::Output {
|
||||
|
||||
let f = self.unit.match_prefix_factor(&other.unit);
|
||||
let mut o = other;
|
||||
if self.unit != o.unit {
|
||||
if self.unit.compatible_with(&o.unit) {
|
||||
o = o.convert_to(self.clone()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
Quantity {
|
||||
scalar: self.scalar * other.scalar * f.scalar,
|
||||
unit: self.unit * other.unit * f.unit,
|
||||
scalar: self.scalar * o.scalar,
|
||||
unit: self.unit * o.unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MulAssign for Quantity where {
|
||||
fn mul_assign(&mut self, other: Self) {
|
||||
let f = self.unit.match_prefix_factor(&other.unit);
|
||||
|
||||
self.scalar *= other.scalar * f.scalar;
|
||||
self.unit *= other.unit * f.unit;
|
||||
let mut o = other;
|
||||
if self.unit != o.unit {
|
||||
if o.unit.compatible_with(&self.unit) {
|
||||
o = o.convert_to(self.clone()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
self.scalar *= o.scalar;
|
||||
self.unit *= o.unit;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,17 +304,33 @@ impl Div for Quantity {
|
|||
type Output = Self;
|
||||
|
||||
fn div(self, other: Self) -> Self::Output {
|
||||
|
||||
let mut o = other;
|
||||
if self.unit != o.unit {
|
||||
if self.unit.compatible_with(&o.unit) {
|
||||
o = o.convert_to(self.clone()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
Quantity {
|
||||
scalar: self.scalar / other.scalar,
|
||||
unit: self.unit / other.unit
|
||||
scalar: self.scalar / o.scalar,
|
||||
unit: self.unit / o.unit
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DivAssign for Quantity where {
|
||||
fn div_assign(&mut self, other: Self) {
|
||||
self.scalar /= other.scalar;
|
||||
self.unit /= other.unit;
|
||||
|
||||
let mut o = other;
|
||||
if self.unit != o.unit {
|
||||
if self.unit.compatible_with(&o.unit) {
|
||||
o = o.convert_to(self.clone()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
self.scalar /= o.scalar;
|
||||
self.unit /= o.unit;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use std::hash::{Hash, Hasher};
|
||||
use std::hash::Hash;
|
||||
|
||||
use crate::quantity::Scalar;
|
||||
use crate::quantity::Quantity;
|
||||
|
@ -8,26 +8,15 @@ use super::Unit;
|
|||
use super::unit_db;
|
||||
|
||||
|
||||
#[derive(Hash)]
|
||||
#[derive(Debug)]
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct FreeUnit {
|
||||
pub (in super) base: UnitBase,
|
||||
pub (in super) prefix: Prefix
|
||||
}
|
||||
|
||||
impl Hash for FreeUnit {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.base.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for FreeUnit {}
|
||||
impl PartialEq for FreeUnit {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.base.eq(&other.base)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
macro_rules! unpack_base_factor {
|
||||
(
|
||||
|
@ -83,11 +72,6 @@ impl FreeUnit {
|
|||
pub fn set_prefix(&mut self, prefix: Prefix) { self.prefix = prefix; }
|
||||
pub fn get_prefix(&self) -> Prefix { self.prefix }
|
||||
|
||||
pub fn same_with_prefix(&self, other: &FreeUnit) -> bool {
|
||||
self.base.eq(&other.base) && self.prefix.eq(&other.prefix)
|
||||
}
|
||||
|
||||
|
||||
pub fn to_base_factor(&self) -> Quantity {
|
||||
|
||||
let q = unit_db!(self.base, unpack_base_factor);
|
||||
|
@ -96,7 +80,7 @@ impl FreeUnit {
|
|||
let mut p = self.prefix.to_ratio();
|
||||
p.insert_unit(FreeUnit::from_base(self.base), Scalar::new_rational(1f64).unwrap());
|
||||
p.insert_unit(FreeUnit::from_base_prefix(self.base, self.prefix), Scalar::new_rational(-1f64).unwrap());
|
||||
q *= p;
|
||||
q.mul_assign_no_convert(p);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
|
|
@ -97,46 +97,11 @@ 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; }
|
||||
pub fn compatible_with(&self, other: &Unit) -> bool {
|
||||
let s = self.clone() * self.to_base_factor().unit;
|
||||
let o = other.clone() * other.to_base_factor().unit;
|
||||
return o == s;
|
||||
}
|
||||
}
|
||||
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.prefix.to_ratio();
|
||||
p.insert_unit(FreeUnit::from_base(ou.base), Scalar::new_rational(1f64).unwrap());
|
||||
p.insert_unit(FreeUnit::from_base_prefix(ou.base, ou.prefix), Scalar::new_rational(-1f64).unwrap());
|
||||
|
||||
// Conversion factor su -> basic
|
||||
let mut q = su.prefix.to_ratio();
|
||||
q.insert_unit(FreeUnit::from_base(su.base), Scalar::new_rational(1f64).unwrap());
|
||||
q.insert_unit(FreeUnit::from_base_prefix(su.base, su.prefix), Scalar::new_rational(-1f64).unwrap());
|
||||
|
||||
f = f * (p / q).pow(Quantity::from_scalar(op.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
|
||||
pub fn insert(&mut self, u: FreeUnit, p: Scalar) {
|
||||
let v = self.get_val_mut();
|
||||
|
@ -165,15 +130,13 @@ impl Unit {
|
|||
|
||||
for (u, p) in self.get_val().iter() {
|
||||
let b = u.to_base_factor();
|
||||
q *= b.pow(Quantity::from_scalar(p.clone()));
|
||||
q.mul_assign_no_convert(b.pow(Quantity::from_scalar(p.clone())));
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
impl Unit {
|
||||
pub fn from_string(s: &str) -> Option<Quantity> {
|
||||
macro_rules! unpack_fromstring {
|
||||
|
@ -220,8 +183,6 @@ impl Unit {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
impl PartialEq for Unit {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
let v = self.get_val();
|
||||
|
@ -231,6 +192,15 @@ impl PartialEq for Unit {
|
|||
None => { return false; }
|
||||
};
|
||||
}
|
||||
|
||||
let v = other.get_val();
|
||||
for (u, p) in self.get_val() {
|
||||
match v.get(u) {
|
||||
Some(i) => { if i != p { return false; } },
|
||||
None => { return false; }
|
||||
};
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -383,7 +383,7 @@ impl Operator{
|
|||
let j = args[i].as_number();
|
||||
if let Token::Number(v) = j {
|
||||
|
||||
if sum.unit() != v.unit() {
|
||||
if !sum.unit.compatible_with(&v.unit) {
|
||||
return Err(EvalError::IncompatibleUnit);
|
||||
}
|
||||
|
||||
|
@ -456,7 +456,7 @@ impl Operator{
|
|||
if let Token::Number(va) = a {
|
||||
if let Token::Number(vb) = b {
|
||||
|
||||
if va.unit() != vb.unit() {
|
||||
if !vb.unitless() {
|
||||
return Err(EvalError::IncompatibleUnit);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue