Fixed unit matching

pull/2/head
Mark 2023-07-28 10:33:51 -07:00
parent 7fb0e0274c
commit 7b77c49ba4
Signed by: Mark
GPG Key ID: AD62BB059C2AAEE4
3 changed files with 60 additions and 9 deletions

View File

@ -111,7 +111,6 @@ impl Quantity {
return Some(n.mul_no_convert(fa).div_no_convert(fb)) return Some(n.mul_no_convert(fa).div_no_convert(fb))
} }
pub fn match_units(&mut self, other: &Quantity) { pub fn match_units(&mut self, other: &Quantity) {
let mut new_units = Quantity::new_rational_from_string("1").unwrap(); let mut new_units = Quantity::new_rational_from_string("1").unwrap();
@ -123,15 +122,16 @@ impl Quantity {
// Check if `us` matches some unit in `other` // Check if `us` matches some unit in `other`
for (uo, _) in other.unit.get_val() { for (uo, _) in other.unit.get_val() {
if { // Use generalized compatible_with check to match reciprocal units
uo.to_base().unit.compatible_with(&us.to_base().unit) // (for example, 1Hz * 1 sec.)
} { let f = uo.to_base().unit.compatible_with_power(&us.to_base().unit);
// If it does, convert `us` to `uo` if f.is_none() { continue; }
new_units.insert_unit(uo.clone(), ps.clone()); let f = f.unwrap();
new_units.insert_unit(uo.clone(), ps.clone() * f);
flag = true; flag = true;
break; break;
} }
}
if !flag { if !flag {
// If no unit in `other` matches `us`, don't convert `us` // If no unit in `other` matches `us`, don't convert `us`
new_units.insert_unit(us.clone(), ps.clone()); new_units.insert_unit(us.clone(), ps.clone());

View File

@ -162,6 +162,55 @@ impl Unit {
return o == s; return o == s;
} }
// True if all base units are the same AND there is a constant factor between their powers.
// This is a generalization of `compatible_with`. `compatible_with` is true iff
// `compatible_with_power` is one.
pub fn compatible_with_power(&self, other: &Unit) -> Option<Scalar> {
let mut flag;
let mut pow_factor: Option<Scalar> = None;
let sbu = self.to_base().unit;
let obu = other.to_base().unit;
for (us, ps) in sbu.get_val() {
flag = false;
for (uo, po) in obu.get_val() {
if uo.whole == us.whole {
if pow_factor.is_none() {
pow_factor = Some(po.clone() / ps.clone());
} else if let Some(ref f) = pow_factor {
if *f != po.clone() / ps.clone() { return None; }
}
flag = true;
break;
}
}
if !flag { return None; }
}
pow_factor = None;
for (uo, po) in obu.get_val() {
flag = false;
for (us, ps) in sbu.get_val() {
if uo.whole == us.whole {
if pow_factor.is_none() {
pow_factor = Some(po.clone() / ps.clone());
} else if let Some(ref f) = pow_factor {
if *f != po.clone() / ps.clone() { return None; }
}
flag = true;
break;
}
}
if !flag { return None; }
}
return pow_factor;
}
pub fn insert(&mut self, u: FreeUnit, p: Scalar) { pub fn insert(&mut self, u: FreeUnit, p: Scalar) {
let v = self.get_val_mut(); let v = self.get_val_mut();
match v.get_mut(&u) { match v.get_mut(&u) {

View File

@ -211,4 +211,6 @@ fn complex_units() {
good_expr("20 mi", "10 mph * 2 hours"); good_expr("20 mi", "10 mph * 2 hours");
good_expr("120 m", "1 (m/s) * 2 min"); good_expr("120 m", "1 (m/s) * 2 min");
good_expr("120 m", "(2 min) * (1 m/s)"); good_expr("120 m", "(2 min) * (1 m/s)");
good_expr("180", "1 Hz * 3 min");
good_expr("3600", "1 hour * 1 Hz");
} }