mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
printf - Update %g formatting to match GNU
This commit is contained in:
parent
ebd0c09549
commit
2afa9cd1a0
2 changed files with 156 additions and 33 deletions
|
@ -5,21 +5,88 @@ use super::super::format_field::FormatField;
|
|||
use super::super::formatter::{FormatPrimitive, Formatter, InitialPrefix};
|
||||
use super::float_common::{get_primitive_dec, primitive_to_str_common, FloatAnalysis};
|
||||
|
||||
fn get_len_fmt_primitive(fmt: &FormatPrimitive) -> usize {
|
||||
let mut len = 0;
|
||||
if let Some(ref s) = fmt.prefix {
|
||||
len += s.len();
|
||||
const SIGNIFICANT_FIGURES: usize = 6;
|
||||
|
||||
fn round_to_significance(input: &str, significant_figures: usize) -> u32 {
|
||||
if significant_figures < input.len() {
|
||||
let digits = &input[..significant_figures + 1];
|
||||
let float_representation = digits.parse::<f32>().unwrap();
|
||||
(float_representation / 10.0).round() as u32
|
||||
} else {
|
||||
input.parse::<u32>().unwrap_or(0)
|
||||
}
|
||||
if let Some(ref s) = fmt.pre_decimal {
|
||||
len += s.len();
|
||||
}
|
||||
|
||||
fn round(mut format: FormatPrimitive) -> FormatPrimitive {
|
||||
let mut significant_figures = SIGNIFICANT_FIGURES;
|
||||
|
||||
if format.pre_decimal.is_some() {
|
||||
let input = format.pre_decimal.as_ref().unwrap();
|
||||
let rounded = round_to_significance(input, significant_figures);
|
||||
let mut rounded_str = rounded.to_string();
|
||||
significant_figures -= rounded_str.len();
|
||||
|
||||
if significant_figures == 0 {
|
||||
if let Some(digits) = &format.post_decimal {
|
||||
if digits.chars().next().unwrap_or('0') >= '5' {
|
||||
let rounded = rounded + 1;
|
||||
rounded_str = rounded.to_string();
|
||||
}
|
||||
if let Some(ref s) = fmt.post_decimal {
|
||||
len += s.len();
|
||||
}
|
||||
if let Some(ref s) = fmt.suffix {
|
||||
len += s.len();
|
||||
}
|
||||
len
|
||||
format.pre_decimal = Some(rounded_str);
|
||||
}
|
||||
|
||||
if significant_figures == 0 {
|
||||
format.post_decimal = Some(String::new());
|
||||
} else if let Some(input) = format.post_decimal {
|
||||
let leading_zeroes = input.len() - input.trim_start_matches('0').len();
|
||||
|
||||
let rounded_str = if leading_zeroes <= significant_figures {
|
||||
let mut post_decimal = String::with_capacity(significant_figures);
|
||||
for _ in 0..leading_zeroes {
|
||||
post_decimal.push('0');
|
||||
}
|
||||
|
||||
significant_figures -= leading_zeroes;
|
||||
let rounded = round_to_significance(&input[leading_zeroes..], significant_figures);
|
||||
post_decimal.push_str(&rounded.to_string());
|
||||
post_decimal
|
||||
} else {
|
||||
input[..significant_figures].to_string()
|
||||
};
|
||||
format.post_decimal = Some(rounded_str);
|
||||
}
|
||||
format
|
||||
}
|
||||
|
||||
fn truncate(mut format: FormatPrimitive) -> FormatPrimitive {
|
||||
if let Some(ref post_dec) = format.post_decimal {
|
||||
let trimmed = post_dec.trim_end_matches('0');
|
||||
|
||||
if trimmed.is_empty() {
|
||||
format.post_decimal = Some("".into());
|
||||
if format.suffix == Some("e+00".into()) {
|
||||
format.suffix = Some("".into());
|
||||
}
|
||||
} else if trimmed.len() != post_dec.len() {
|
||||
format.post_decimal = Some(trimmed.to_owned());
|
||||
}
|
||||
}
|
||||
format
|
||||
}
|
||||
|
||||
fn is_float_magnitude(suffix: &Option<String>) -> bool {
|
||||
match suffix {
|
||||
Some(exponent) => {
|
||||
if exponent.chars().nth(1) == Some('-') {
|
||||
exponent < &"e-05".into()
|
||||
} else {
|
||||
exponent < &"e+06".into()
|
||||
}
|
||||
}
|
||||
None => true,
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Decf;
|
||||
|
@ -46,34 +113,26 @@ impl Formatter for Decf {
|
|||
None,
|
||||
false,
|
||||
);
|
||||
let mut f_sci = get_primitive_dec(
|
||||
let mut f_dec = get_primitive_dec(
|
||||
initial_prefix,
|
||||
&str_in[initial_prefix.offset..],
|
||||
&analysis,
|
||||
second_field as usize,
|
||||
Some(*field.field_char == 'G'),
|
||||
);
|
||||
// strip trailing zeroes
|
||||
if let Some(ref post_dec) = f_sci.post_decimal {
|
||||
let trimmed = post_dec.trim_end_matches('0');
|
||||
if trimmed.len() != post_dec.len() {
|
||||
f_sci.post_decimal = Some(trimmed.to_owned());
|
||||
}
|
||||
}
|
||||
let f_fl = get_primitive_dec(
|
||||
|
||||
if is_float_magnitude(&f_dec.suffix) {
|
||||
f_dec = get_primitive_dec(
|
||||
initial_prefix,
|
||||
&str_in[initial_prefix.offset..],
|
||||
&analysis,
|
||||
second_field as usize,
|
||||
None,
|
||||
);
|
||||
Some(
|
||||
if get_len_fmt_primitive(&f_fl) >= get_len_fmt_primitive(&f_sci) {
|
||||
f_sci
|
||||
} else {
|
||||
f_fl
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
f_dec = truncate(round(f_dec));
|
||||
Some(f_dec)
|
||||
}
|
||||
fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
|
||||
primitive_to_str_common(prim, &field)
|
||||
|
|
|
@ -289,7 +289,7 @@ fn sub_num_dec_trunc() {
|
|||
new_ucmd!()
|
||||
.args(&["pi is ~ %g", "3.1415926535"])
|
||||
.succeeds()
|
||||
.stdout_only("pi is ~ 3.141593");
|
||||
.stdout_only("pi is ~ 3.14159");
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "test_unimplemented"), ignore)]
|
||||
|
@ -469,3 +469,67 @@ fn sub_float_leading_zeroes() {
|
|||
.succeeds()
|
||||
.stdout_only("001.000000");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_float() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "1.1"])
|
||||
.succeeds()
|
||||
.stdout_only("1.1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_truncate_to_integer() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "1.0"])
|
||||
.succeeds()
|
||||
.stdout_only("1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_prefix_with_spaces() {
|
||||
new_ucmd!()
|
||||
.args(&["%5g", "1.1"])
|
||||
.succeeds()
|
||||
.stdout_only(" 1.1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_large_integer() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "1000000"])
|
||||
.succeeds()
|
||||
.stdout_only("1e+06");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_round_scientific_notation() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "123456789"])
|
||||
.succeeds()
|
||||
.stdout_only("1.23457e+08");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_scientific_leading_zeroes() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "1000010"])
|
||||
.succeeds()
|
||||
.stdout_only("1.00001e+06");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_round_float() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "12345.6789"])
|
||||
.succeeds()
|
||||
.stdout_only("12345.7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sub_general_round_float_to_integer() {
|
||||
new_ucmd!()
|
||||
.args(&["%g", "123456.7"])
|
||||
.succeeds()
|
||||
.stdout_only("123457");
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue