Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Partially fix printf hex float numbers/%a rounding #1286

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions libc/stdio/fmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -690,26 +690,45 @@ static int __fmt_fpiprec(struct FPBits *b) {
// prec1 = incoming precision (after ".")
static int __fmt_bround(struct FPBits *b, int prec, int prec1) {
uint32_t *bits, t;
int i, inc, j, k, m, n;
int i, j, k, m, n;
bool inc = false;
int current_rounding_mode;
m = prec1 - prec;
bits = b->bits;
inc = 0;
k = m - 1;

// The first two ifs here handle cases where rounding is simple, i.e. where we
// always know in which direction we must round because of the current
// rounding mode (note that if the correct value for inc is `false` then it
// doesn't need to be set as we have already done so above)
// The last one handles rounding to nearest
current_rounding_mode = fegetround();
if (current_rounding_mode == FE_TOWARDZERO ||
(current_rounding_mode == FE_UPWARD && b->sign) ||
(current_rounding_mode == FE_DOWNWARD && !b->sign))
goto have_inc;
if ((current_rounding_mode == FE_UPWARD && !b->sign) ||
(current_rounding_mode == FE_DOWNWARD && b->sign)) {
inc = true;
goto have_inc;
}

if ((t = bits[k >> 3] >> (j = (k & 7) * 4)) & 8) {
if (t & 7)
goto inc1;
goto inc_true;
if (j && bits[k >> 3] << (32 - j))
goto inc1;
goto inc_true;
while (k >= 8) {
k -= 8;
if (bits[k >> 3]) {
inc1:
inc = 1;
goto haveinc;
inc_true:
inc = true;
goto have_inc;
}
}
}
haveinc:

have_inc:
b->ex += m * 4;
i = m >> 3;
k = prec1 >> 3;
Expand Down
34 changes: 34 additions & 0 deletions test/libc/stdio/snprintf_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,37 @@ TEST(snprintf, testLongDoubleRounding) {

ASSERT_EQ(0, fesetround(previous_rounding));
}

TEST(snprintf, testAConversionSpecifierRounding) {
int previous_rounding = fegetround();
ASSERT_EQ(0, fesetround(FE_DOWNWARD));

char buf[20];
int i = snprintf(buf, sizeof(buf), "%.1a", 0x1.fffffp+4);
ASSERT_EQ(8, i);
ASSERT_STREQ("0x1.fp+4", buf);

ASSERT_EQ(0, fesetround(FE_UPWARD));

i = snprintf(buf, sizeof(buf), "%.1a", 0x1.f8p+4);
ASSERT_EQ(8, i);
ASSERT_STREQ("0x2.0p+4", buf);

ASSERT_EQ(0, fesetround(previous_rounding));
}

// This test currently fails because of rounding issues
// If that ever gets fixed, uncomment this
/*
TEST(snprintf, testAConversionSpecifier) {
char buf[20];
int i = snprintf(buf, sizeof(buf), "%.1a", 0x1.7800000000001p+4);
ASSERT_EQ(8, i);
ASSERT_STREQ("0x1.8p+4", buf);

memset(buf, 0, sizeof(buf));
i = snprintf(buf, sizeof(buf), "%.1a", 0x1.78p+4);
ASSERT_EQ(8, i);
ASSERT_STREQ("0x1.8p+4", buf);
}
*/
Loading