Fix engineering format bug

This commit is contained in:
Austen Adler 2021-05-13 21:59:05 -04:00
parent db21c7a858
commit bab2904495
2 changed files with 32 additions and 5 deletions

2
Cargo.lock generated
View File

@ -127,7 +127,7 @@ dependencies = [
[[package]] [[package]]
name = "rpn_rs" name = "rpn_rs"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"confy", "confy",
"serde", "serde",

View File

@ -410,7 +410,7 @@ fn fmt_scientific(f: f64, precision: usize) -> String {
fn fmt_engineering(f: f64, precision: usize) -> String { fn fmt_engineering(f: f64, precision: usize) -> String {
// Format the string so the first digit is always in the first column, and remove '.'. Requested precision + 2 to account for using 1, 2, or 3 digits for the whole portion of the string // Format the string so the first digit is always in the first column, and remove '.'. Requested precision + 2 to account for using 1, 2, or 3 digits for the whole portion of the string
// 1,000 => 1000E3 // 1,000 => 1000E3
let all = format!("{:.precision$E}", f, precision = precision + 2).replacen(".", "", 1); let all = format!(" {:.precision$E}", f, precision = precision + 2).replacen(".", "", 1);
// Extract mantissa and the string representation of the exponent. Unwrap should be safe as formatter will insert E // Extract mantissa and the string representation of the exponent. Unwrap should be safe as formatter will insert E
// 1000E3 => (1000, E3) // 1000E3 => (1000, E3)
let (num_str, exp_str) = all.split_at(all.find('E').unwrap()); let (num_str, exp_str) = all.split_at(all.find('E').unwrap());
@ -429,14 +429,23 @@ fn fmt_engineering(f: f64, precision: usize) -> String {
let display_exp = (exp.div_euclid(3) * 3).abs(); let display_exp = (exp.div_euclid(3) * 3).abs();
// Number of whole digits. Always 1, 2, or 3 depending on exponent divisibility // Number of whole digits. Always 1, 2, or 3 depending on exponent divisibility
let num_whole_digits = exp.rem_euclid(3) as usize + 1; let num_whole_digits = exp.rem_euclid(3) as usize + 1;
// If this is a negative number, strip off the added space, otherwise keep the space (and next digit)
let num_str = if let Some(_) = num_str.strip_prefix(" -") {
&num_str[1..]
} else {
num_str
};
// Whole portion of number. Slice is safe because the num_whole_digits is always 3 and the num_str will always have length >= 3 since precision in all=2 (+original whole digit) // Whole portion of number. Slice is safe because the num_whole_digits is always 3 and the num_str will always have length >= 3 since precision in all=2 (+original whole digit)
// Original number is 1,000 => whole will be 1, if original is 0.01, whole will be 10 // Original number is 1,000 => whole will be 1, if original is 0.01, whole will be 10
let whole = &num_str[0..num_whole_digits]; let whole = &num_str[0..(num_whole_digits + 1)];
// Decimal portion of the number. Sliced from the number of whole digits to the *requested* precision. Precision generated in all will be requested precision + 2 // Decimal portion of the number. Sliced from the number of whole digits to the *requested* precision. Precision generated in all will be requested precision + 2
let decimal = &num_str[num_whole_digits..(precision + num_whole_digits)]; let decimal = &num_str[(num_whole_digits + 1)..(precision + num_whole_digits + 1)];
// Right align whole portion, always have decimal point // Right align whole portion, always have decimal point
format!( format!(
"{: >3}.{} E{}{:0>pad$}", "{: >4}.{} E{}{:0>pad$}",
// display_sign,
whole, whole,
decimal, decimal,
display_exp_sign, display_exp_sign,
@ -503,4 +512,22 @@ mod tests {
assert_eq!(fmt_separated(f, c), s); assert_eq!(fmt_separated(f, c), s);
} }
} }
#[test]
fn test_fmt_engineering() {
for (f, c, s) in vec![
(100.0, 3, " 100.000 E+00"),
(100.0, 3, " 100.000 E+00"),
(-100.0, 3, "-100.000 E+00"),
(100.0, 0, " 100. E+00"),
(-100.0, 0, "-100. E+00"),
(0.1, 2, " 100.00 E-03"),
(0.01, 2, " 10.00 E-03"),
(0.001, 2, " 1.00 E-03"),
(0.0001, 2, " 100.00 E-06"),
// Rounding
] {
assert_eq!(fmt_engineering(f, c), s);
}
}
} }