Skip to content

fix: take exponent after rounding in %e and %g - #29

Merged
MaJerle merged 1 commit into
MaJerle:developfrom
emincan2000:fix-exponent-rounding-carry
Oct 26, 2026
Merged

MaJerle merged 1 commit into
MaJerle:developfrom
emincan2000:fix-exponent-rounding-carry

Conversation

@emincan2000

Copy link
Copy Markdown
Contributor

When rounding carries into a new digit, %e prints a two digit mantissa because the exponent is counted before the number is rounded:

lwprintf_snprintf(buf, sizeof(buf), "%.1e", 9.96);   // "10.0e+00", expected "1.0e+01"
lwprintf_snprintf(buf, sizeof(buf), "%.0e", 0.0996); // "10e-02",   expected "1e-01"

%g has the same issue when it picks between f and e style, since the standard uses the exponent after rounding to P - 1 digits:

"%g",   999999.7   // "1000000", expected "1e+06"
"%.2g", 99.96      // "100",     expected "1e+02"
"%.1g", 0.0000997  // "10e-05",  expected "0.0001"

The fix rounds once in e style before the decision, and if the result reached 10 it bumps the exponent and continues with 1.0. The rest of the code is unchanged.

I added these cases to test_basic.c. I also compared against glibc snprintf with random values for %e, %.0e, %.1e, %.3e, %g, %.1g, %.2g, %.3g, %#g, %E, %G and with widths. Every mismatch that went away was one of these carry cases, and no new mismatch appeared. The ones left are the round-half-to-even differences already mentioned in the comment in prv_calculate_dbl_num_data.

I could only build the tests natively on 64-bit here, so the three %p tests that assume a 32-bit pointer fail locally both with and without this change.

The number is normalized and the exponent counted before it is rounded
to the precision. When rounding carries into a new digit the exponent was
not updated, so 9.96 with "%.1e" printed "10.0e+00" instead of "1.0e+01".

%g had the same problem when choosing between 'f' and 'e' style, e.g.
999999.7 with "%g" printed "1000000" instead of "1e+06".
@MaJerle
MaJerle merged commit 920135e into MaJerle:develop Oct 26, 2026
2 checks passed
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.

2 participants