Adjusted estimation and rounding to include imaginary numbers

This commit is contained in:
bakk 2021-05-20 20:50:24 +02:00
parent aeef49e9ef
commit 1c914bc77f

View File

@ -326,8 +326,68 @@ impl KalkNum {
/// Get an estimate of what the number is, eg. 3.141592 => π /// Get an estimate of what the number is, eg. 3.141592 => π
pub fn estimate(&self) -> Option<String> { pub fn estimate(&self) -> Option<String> {
let fract = self.value.clone().fract().abs(); let rounded_real = self.estimate_one_value(ComplexNumberType::Real);
let integer = self.value.clone().trunc(); let rounded_imaginary = self.estimate_one_value(ComplexNumberType::Imaginary);
if let (None, None) = (&rounded_real, &rounded_imaginary) {
return None;
}
let mut output = String::new();
if let Some(value) = rounded_real {
output.push_str(&value);
}
if let Some(value) = rounded_imaginary {
// Clear output if it's just 0.
if output == "0" {
output = String::new();
}
if value != "0" {
// If there is a real value as well
if output.len() > 0 {
output.push_str(" + ");
}
output.push_str(&format!("{}i", value));
}
}
Some(output)
}
/// Basic up/down rounding from 0.00xxx or 0.999xxx or xx.000xxx, etc.
pub fn round(&self) -> Option<KalkNum> {
let rounded_real = self.round_one_value(ComplexNumberType::Real);
let rounded_imaginary = self.round_one_value(ComplexNumberType::Imaginary);
if let (None, None) = (&rounded_real, &rounded_imaginary) {
return None;
}
Some(KalkNum::new_with_imaginary(
rounded_real.unwrap_or(self.clone()).value,
&self.unit,
rounded_imaginary.unwrap_or(self.clone()).imaginary_value,
))
}
pub fn round_if_needed(&self) -> KalkNum {
if let Some(value) = self.round() {
value
} else {
self.clone() // Hmm
}
}
pub fn estimate_one_value(&self, complex_number_type: ComplexNumberType) -> Option<String> {
let (value, value_string) = match complex_number_type {
ComplexNumberType::Real => (&self.value, self.to_string()),
ComplexNumberType::Imaginary => (&self.imaginary_value, self.to_string_imaginary(true)),
};
let fract = value.clone().fract().abs();
let integer = value.clone().trunc();
// If it's an integer, there's nothing that would be done to it. // If it's an integer, there's nothing that would be done to it.
if fract == 0f64 { if fract == 0f64 {
@ -335,8 +395,8 @@ impl KalkNum {
} }
// Eg. 0.5 to 1/2 // Eg. 0.5 to 1/2
let as_abs_string = self.to_string().trim_start_matches("-").to_string(); let as_abs_string = value_string.trim_start_matches("-").to_string();
let sign = if self.value < 0f64 { "-" } else { "" }; let sign = if *value < 0f64 { "-" } else { "" };
let fract_as_string = fract.to_string(); let fract_as_string = fract.to_string();
if as_abs_string.starts_with("0.5") { if as_abs_string.starts_with("0.5") {
if as_abs_string.len() == 3 || (as_abs_string.len() > 6 && &as_abs_string[3..5] == "00") if as_abs_string.len() == 3 || (as_abs_string.len() > 6 && &as_abs_string[3..5] == "00")
@ -377,15 +437,18 @@ impl KalkNum {
} }
// If nothing above was relevant, simply round it off a bit, eg. from 0.99999 to 1 // If nothing above was relevant, simply round it off a bit, eg. from 0.99999 to 1
let rounded = self.round()?.to_string(); let rounded = self.round_one_value(complex_number_type)?.to_string();
Some(trim_zeroes(&rounded)) Some(trim_zeroes(&rounded))
} }
/// Basic up/down rounding from 0.00xxx or 0.999xxx or xx.000xxx, etc. fn round_one_value(&self, complex_number_type: ComplexNumberType) -> Option<KalkNum> {
pub fn round(&self) -> Option<KalkNum> { let value = match complex_number_type {
let sign = if self.value < 0f64 { -1f64 } else { 1f64 }; ComplexNumberType::Real => &self.value,
let fract = self.value.clone().abs().fract(); ComplexNumberType::Imaginary => &self.imaginary_value,
let integer = self.value.clone().abs().trunc(); };
let sign = if *value < 0f64 { -1f64 } else { 1f64 };
let fract = value.clone().abs().fract();
let integer = value.clone().abs().trunc();
// If it's zero something, don't do the rounding as aggressively. // If it's zero something, don't do the rounding as aggressively.
let (limit_floor, limit_ceil) = if integer == 0f64 { let (limit_floor, limit_ceil) = if integer == 0f64 {
@ -400,22 +463,11 @@ impl KalkNum {
} else if (1f64 - fract.clone()).log10() < limit_ceil { } else if (1f64 - fract.clone()).log10() < limit_ceil {
// If eg. 0.999 // If eg. 0.999
// .abs() this before ceiling to make sure it rounds correctly. The sign is re-added afterwards. // .abs() this before ceiling to make sure it rounds correctly. The sign is re-added afterwards.
Some(KalkNum::new( Some(KalkNum::new(value.clone().abs().ceil() * sign, &self.unit))
self.value.clone().abs().ceil() * sign,
&self.unit,
))
} else { } else {
None None
} }
} }
pub fn round_if_needed(&self) -> KalkNum {
if let Some(value) = self.round() {
value
} else {
self.clone() // Hmm
}
}
} }
fn trim_number_string(input: &str) -> String { fn trim_number_string(input: &str) -> String {