diff --git a/src/main.rs b/src/main.rs index 6b135e3..9579c17 100644 --- a/src/main.rs +++ b/src/main.rs @@ -403,62 +403,42 @@ fn fmt_scientific(f: f64, precision: usize) -> String { let sign = if !ret.starts_with('-') { " " } else { "" }; 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 - -// fn fmt_engineering(i: usize, f: f64, precision: usize) -> String { -// // 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[()..()] -// let first_three = match exp { -// } -// let (pow_sign, exp) = if exp.starts_with("E-") { -// ('-', &exp[2..]) -// } else { -// ('+', &exp[1..]) -// }; -// let sign = if !ret.starts_with('-') { " " } else { "" }; -// format!( -// "{:>2}: {}{}e{}{:0>pad$}", -// i, -// sign, -// ret, -// pow_sign, -// exp, -// pad = 2 -// ) -// } 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 + // 1,000 => 1000E3 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-") { + // Extract mantissa and the string representation of the exponent. Unwrap should be safe as formatter will insert E + // 1000E3 => (1000, E3) + let (num_str, exp_str) = all.split_at(all.find('E').unwrap()); + // Extract the exponent as an isize. This should always be true because f64 max will be ~400 + // E3 => 3 as isize + let exp = exp_str[1..].parse::().unwrap(); + // Sign of the exponent. If string representation starts with E-, then negative + let display_exp_sign = if let Some(stripped) = exp_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..]; + + // The exponent to display. Always a multiple of 3 in engineering mode. Always positive because sign is added with display_exp_sign above + // 100 => 0, 1000 => 3, .1 => 3 (but will show as -3) + let display_exp = (exp.div_euclid(3) * 3).abs(); + // Number of whole digits. Always 1, 2, or 3 depending on exponent divisibility + let num_whole_digits = exp.rem_euclid(3) as usize + 1; + // 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 + let whole = &num_str[0..num_whole_digits]; + // 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)]; + // Right align whole portion, always have decimal point format!( - "{: >3}.{} * 10 ^ {}{}", - whole, decimal, display_pow_sign, display_pow + "{: >3}.{} E{}{:0>pad$}", + whole, + decimal, + display_exp_sign, + display_exp, + pad = 2 ) }