From 1ccc950afe0e57f8a1ec37c652f1718b6181028c Mon Sep 17 00:00:00 2001 From: Austen Adler Date: Thu, 6 May 2021 01:12:17 -0400 Subject: [PATCH] Start work on engineering display mode --- src/calc/constants.rs | 2 +- src/main.rs | 129 +++++++++++++++++++++++++----------------- 2 files changed, 79 insertions(+), 52 deletions(-) diff --git a/src/calc/constants.rs b/src/calc/constants.rs index e7a4e99..75740ab 100644 --- a/src/calc/constants.rs +++ b/src/calc/constants.rs @@ -85,7 +85,7 @@ impl fmt::Display for CalculatorDisplayMode { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { CalculatorDisplayMode::Default => write!(f, "DEF"), - CalculatorDisplayMode::Separated(c) => write!(f, "DEF({})", c), + CalculatorDisplayMode::Separated(c) => write!(f, "SEP({})", c), CalculatorDisplayMode::Scientific(p) => write!(f, "SCI({})", p), CalculatorDisplayMode::Engineering(p) => write!(f, "ENG({})", p), CalculatorDisplayMode::Fixed(p) => write!(f, "FIX({})", p), diff --git a/src/main.rs b/src/main.rs index 8c46457..6b135e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -119,12 +119,14 @@ fn main() -> Result<(), Box> { let content = vec![Spans::from(Span::raw( match app.calculator.get_display_mode() { CalculatorDisplayMode::Default => format!("{:>2}: {}", i, *m), - CalculatorDisplayMode::Separated(c) => fmt_separated(i, *m, *c), - CalculatorDisplayMode::Scientific(precision) => { - fmt_scientific(i, *m, *precision) + CalculatorDisplayMode::Separated(c) => { + format!("{:>2}: {}", i, fmt_separated(*m, *c)) } - CalculatorDisplayMode::Engineering(_precision) => { - format!("{:>2}: {}", i, m) + CalculatorDisplayMode::Scientific(precision) => { + format!("{:>2}: {}", i, fmt_scientific(*m, *precision)) + } + CalculatorDisplayMode::Engineering(precision) => { + format!("{:>2}: {}", i, fmt_engineering(*m, *precision)) } CalculatorDisplayMode::Fixed(precision) => { format!("{:>2}: {:.precision$}", i, m, precision = precision) @@ -389,30 +391,36 @@ fn draw_clippy_rect(c: ClippyRectangle, f: &mut Frame String { +fn fmt_scientific(f: f64, precision: usize) -> String { let mut ret = format!("{:.precision$E}", f, precision = precision); let exp = ret.split_off(ret.find('E').unwrap_or(0)); - let (pow_sign, exp) = if let Some(stripped) = exp.strip_prefix("E-") { + let (exp_sign, exp) = if let Some(stripped) = exp.strip_prefix("E-") { ('-', stripped) } else { ('+', &exp[1..]) }; let sign = if !ret.starts_with('-') { " " } else { "" }; - format!( - "{:>2}: {}{}E{}{:0>pad$}", - i, - sign, - ret, - pow_sign, - exp, - pad = 2 - ) + format!("{}{}E{}{:0>pad$}", sign, ret, exp_sign, exp, pad = 2) } +// (a)E(c) +// E power = f.log10().div_euclid(3) * 3 +// left portion = f.log10().rem_euclid(3) + 1 +// .0001 - 100E-6 - 1E-4 +// .001 - 1E-3 - 1E-3 => -3 +// .01 - 10E-3 - 1E-2 +// .1 - 100E-3 - 1E-1 +// 1 - 1E+0 - 1E+0 => 0 +// 10 - 10E+0 - 1E+1 +// 100 - 100E+0 - 1E+2 +// 1000 - 1E+3 - 1E+3 => 3 +// 10000 - 10E+3 - 1E+4 -// // 100 E+3 // fn fmt_engineering(i: usize, f: f64, precision: usize) -> String { -// let mut ret = format!(" {:.precision$e}", f, precision = precision + 2); +// // TODO: There is probably a more efficent way to do this using slices or something +// let mut all = format!("{:.precision$e}", f, precision = precision + 2).replacen(".", "", 1); +// // The left 1, 2, or 3 digits +// let left = all.split_off(f.log10().rem_euclid(3) + 1); // // The length of ret will always be at least 5 -- 2 leading spaces, integer portion, and precision + 2 // let exp = ret.split_off(ret.find('E').unwrap_or(0)); // let left = ret[()..()] @@ -435,14 +443,33 @@ fn fmt_scientific(i: usize, f: f64, precision: usize) -> String { // ) // } -fn fmt_separated(i: usize, f: f64, sep: char) -> String { +fn fmt_engineering(f: f64, precision: usize) -> String { + let all = format!("{:.precision$E}", f, precision = precision + 2).replacen(".", "", 1); + let (mantissa_str, pow_str) = all.split_at(all.find('E').unwrap_or(0)); + let pow = pow_str[1..].parse::().unwrap(); + let display_pow_sign = if let Some(stripped) = pow_str.strip_prefix("E-") { + '-' + } else { + '+' + }; + let display_pow = (pow.div_euclid(3) * 3).abs(); + let num_digits = pow.rem_euclid(3) as usize + 1; + let whole = &mantissa_str[0..num_digits]; + let decimal = &mantissa_str[num_digits..]; + format!( + "{: >3}.{} * 10 ^ {}{}", + whole, decimal, display_pow_sign, display_pow + ) +} + +fn fmt_separated(f: f64, sep: char) -> String { let mut ret = f.to_string(); let start = if ret.starts_with('-') { 1 } else { 0 }; let end = ret.find('.').unwrap_or_else(|| ret.len()); for i in 0..((end - start - 1).div_euclid(3)) { ret.insert(end - (i + 1) * 3, sep); } - format!("{:>2}: {}", i, ret) + format!("{}", ret) } #[cfg(test)] @@ -450,47 +477,47 @@ mod tests { use super::*; #[test] fn test_fmt_scientific() { - for (i, f, p, s) in vec![ + for (f, p, s) in vec![ // Basic - (0, 1.0, 0, " 0: 1E+00"), - (0, -1.0, 0, " 0: -1E+00"), - (0, 100.0, 0, " 0: 1E+02"), - (0, 0.1, 0, " 0: 1E-01"), - (0, 0.01, 0, " 0: 1E-02"), - (0, -0.1, 0, " 0: -1E-01"), + (1.0, 0, " 1E+00"), + (-1.0, 0, "-1E+00"), + (100.0, 0, " 1E+02"), + (0.1, 0, " 1E-01"), + (0.01, 0, " 1E-02"), + (-0.1, 0, "-1E-01"), // i - (22, 1.0, 0, "22: 1E+00"), + (1.0, 0, " 1E+00"), // Precision - (0, -0.123456789, 3, " 0: -1.235E-01"), - (0, -0.123456789, 2, " 0: -1.23E-01"), - (0, -0.123456789, 2, " 0: -1.23E-01"), - (0, -1e99, 2, " 0: -1.00E+99"), - (0, -1e100, 2, " 0: -1.00E+100"), + (-0.123456789, 3, "-1.235E-01"), + (-0.123456789, 2, "-1.23E-01"), + (-0.123456789, 2, "-1.23E-01"), + (-1e99, 2, "-1.00E+99"), + (-1e100, 2, "-1.00E+100"), ] { - assert_eq!(fmt_scientific(i, f, p), s); + assert_eq!(fmt_scientific(f, p), s); } } #[test] fn test_fmt_separated() { - for (i, f, c, s) in vec![ - (10, 100.0, ',', "10: 100"), - (0, 100.0, ',', " 0: 100"), - (0, -100.0, ',', " 0: -100"), - (0, 1_000.0, ',', " 0: 1,000"), - (0, -1_000.0, ',', " 0: -1,000"), - (0, 10_000.0, ',', " 0: 10,000"), - (0, -10_000.0, ',', " 0: -10,000"), - (0, 100_000.0, ',', " 0: 100,000"), - (0, -100_000.0, ',', " 0: -100,000"), - (0, 1_000_000.0, ',', " 0: 1,000,000"), - (0, -1_000_000.0, ',', " 0: -1,000,000"), - (0, 1_000_000.123456789, ',', " 0: 1,000,000.123456789"), - (0, -1_000_000.123456789, ',', " 0: -1,000,000.123456789"), - (0, 1_000_000.123456789, ' ', " 0: 1 000 000.123456789"), - (0, 1_000_000.123456789, ' ', " 0: 1 000 000.123456789"), + for (f, c, s) in vec![ + (100.0, ',', "100"), + (100.0, ',', "100"), + (-100.0, ',', "-100"), + (1_000.0, ',', "1,000"), + (-1_000.0, ',', "-1,000"), + (10_000.0, ',', "10,000"), + (-10_000.0, ',', "-10,000"), + (100_000.0, ',', "100,000"), + (-100_000.0, ',', "-100,000"), + (1_000_000.0, ',', "1,000,000"), + (-1_000_000.0, ',', "-1,000,000"), + (1_000_000.123456789, ',', "1,000,000.123456789"), + (-1_000_000.123456789, ',', "-1,000,000.123456789"), + (1_000_000.123456789, ' ', "1 000 000.123456789"), + (1_000_000.123456789, ' ', "1 000 000.123456789"), ] { - assert_eq!(fmt_separated(i, f, c), s); + assert_eq!(fmt_separated(f, c), s); } } }