Skip to content

numfmt: round values printed without a suffix - #15636

Open
ozenyunus35 wants to merge 2 commits into
uutils:mainfrom
ozenyunus35:numfmt-round-no-suffix
Open

ozenyunus35 wants to merge 2 commits into
uutils:mainfrom
ozenyunus35:numfmt-round-no-suffix

Conversation

@ozenyunus35

@ozenyunus35 ozenyunus35 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #15574

With --to=si, --to=iec or --to=iec-i, a value printed without a suffix did not use --round:

  • The value was printed with format_float(i2, 0), which rounds half to even. So --to=si 12.1 gave 12 instead of 13, the default from-zero result.
  • consider_suffix checked the unrounded value against bases[1] - 1.0. So --round=down 999.9 got a suffix and printed 0.9k, where GNU prints 999.

consider_suffix now rounds the value with the method first and leaves it without a suffix if the rounded value still fits. It uses div_round, or round_with_precision(.., 0) when a --format precision is given, matching how each case is printed later, and returns that rounded value, so transform_to does not round it again. Values below 10 keep one decimal and are then printed with ties to even, as before. GNU does the same: with the default method, 1.45 gives 2 and 2.5 gives 2, and the results from #12032 (1.4 and 0.6 give 1) stay the same.

export LC_ALL=C
numfmt --to=si 12.1 99.1
# before: 12 / 99
# after:  13 / 100    (same as GNU 9.12)

numfmt --to=si --round=down 999.9
# before: 0.9k
# after:  999         (same as GNU 9.12)

numfmt --to=iec --round=down 1023.9
# before: 0.9K
# after:  1023        (same as GNU 9.12)

I added test_round_without_suffix, which checks all five methods with --to=si, --to=iec and --format=%.1f. It fails without the change, and all test_numfmt tests and the uu_numfmt unit tests pass.

I also compared 90 option combinations with GNU 9.12 in the C locale: --to=si/iec/iec-i, each --round method, and no format, --format=%f/%.0f/%.1f/%.2f and --padding=8. The input was 36 values between -999.9 and 999999, including values near 10, 999 and 1023. Before the change most of them differed. After it the output is the same, except for one input: -0.6 with --round=up or towards-zero and a --format precision prints -0 (or -0.0), where GNU prints 0. That is already the case on main and is not changed here.

cargo bench -p uu_numfmt shows no change against the merge base.

I used an AI assistant to help draft parts of the code and tests; I reviewed the changes and ran the tests myself.

Comment thread src/uu/numfmt/src/format.rs Outdated
div_round(n, 1.0, round_method)
};
if unscaled.abs() <= bases[1] - 1.0 {
return Ok((n, None));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not return unscaled here? then transform_to wouldn't need to round it again

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sylvestre Thanks! consider_suffix now returns unscaled for the no-suffix case, so transform_to prints it without rounding again. Below 10 the two steps (one decimal, then ties to even) are what GNU 9.12 does too: with the default from-zero, 1.45 gives 2, 2.5 gives 2 and 0.5 gives 0, and uutils now gives the same. I also added a --format=%.1f case for all five methods to test_round_without_suffix.

Comment thread src/uu/numfmt/src/format.rs Outdated
localize(format_float(i2, precision))
}
None => localize(format_float(i2, 0)),
None => localize(format_float(div_round(i2, 1.0, round_method), 0)),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

below 10 this rounds twice now (one decimal, then ties-even), so 1.45 gives 2 but 2.5 gives 2, is that what GNU does?
could you please add 1.45 / 2.5 / 9.95 to the test?

}

#[test]
fn test_round_without_suffix() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please add a --format=%.1f case too, the precision branch isn't covered

With --to=si/iec, a value printed without a suffix ignored --round, and
the suffix was picked from the unrounded value, so 999.9 with
--round=down became 0.9k instead of 999.

Fixes uutils#15574
Also cover the --format precision branch in the test.
@sylvestre
sylvestre force-pushed the numfmt-round-no-suffix branch from f9df462 to 678a252 Compare October 25, 2026 13:08

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

numfmt: --to=si/--to=iec ignores --round for values from 10 to 999 that get no suffix

2 participants