Skip to content

Commit

Permalink
uucore:format:fix floating-point rounding
Browse files Browse the repository at this point in the history
Handle a special case for floating-point numbers when |f| < 1.0.

In this case, the total number of decimal places should include both the
padding zeros which are not subject to precision rounding and the
significant digits, rounded according to the precision parameter.
  • Loading branch information
alexs-sh committed Dec 30, 2024
1 parent a669b44 commit f4b248e
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 1 deletion.
30 changes: 29 additions & 1 deletion src/uucore/src/lib/features/format/num_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,23 @@ fn format_float_shortest(
// of digits instead of the digits in the fractional part.
// - If we don't force the decimal, `.` and trailing `0` in the fractional part
// are trimmed.
let decimal_places = (precision as i32 - exponent) as usize;
let decimal_places = if f.abs() >= 1.0 {
(precision as i32 - exponent) as usize
} else {
// This is a special case for |f| < 1.0.
//
// `decimal_places` is calculated as the sum of the padding zeros on the left
// and the number of significant digits. The precision parameter applies only
// to the significant digits.
//
// For example, the number 0.01171875 with a precision of 6 should be interpreted as
// 2 padding zeros and 7 significant digits (1171875). Applying the precision parameter
// to 1171875 results in the number 117188.
//
// So, the final result is 0.0117188.
let padding_zeros = -f.abs().log10().floor() as usize;
precision + padding_zeros
};
let mut formatted = if decimal_places == 0 && force_decimal == ForceDecimal::Yes {
format!("{f:.0}.")
} else {
Expand Down Expand Up @@ -665,4 +681,16 @@ mod test {
assert_eq!(&f("1000.02030"), "1000.0203");
assert_eq!(&f("1000.00000"), "1000");
}

#[test]
fn shortest_float_less_than_one() {
use super::format_float_shortest;
let f = |x| format_float_shortest(x, 6, Case::Lowercase, ForceDecimal::No);
assert_eq!(f(0.1171875), "0.117188");
assert_eq!(f(-0.1171875), "-0.117188");
assert_eq!(f(0.01171875), "0.0117188");
assert_eq!(f(-0.01171875), "-0.0117188");
assert_eq!(f(0.001171875), "0.00117187");
assert_eq!(f(-0.001171875), "-0.00117187");
}
}
24 changes: 24 additions & 0 deletions tests/by-util/test_printf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -916,3 +916,27 @@ fn float_flag_position_space_padding() {
.succeeds()
.stdout_only(" +1.0");
}

#[test]
fn float_less_than_one() {
new_ucmd!()
.args(&["%g", "0.1171875"])
.succeeds()
.stdout_only("0.117188");

// The original value from #7031 issue
new_ucmd!()
.args(&["%g", "-0.1171875"])
.succeeds()
.stdout_only("-0.117188");

new_ucmd!()
.args(&["%g", "0.01171875"])
.succeeds()
.stdout_only("0.0117188");

new_ucmd!()
.args(&["%g", "-0.01171875"])
.succeeds()
.stdout_only("-0.0117188");
}

0 comments on commit f4b248e

Please sign in to comment.