mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Partially fix printf hex float numbers/%a rounding (#1286)
Hexadecimal printing of floating-point numbers in cosmopolitan (that is, using the the conversion specifier) is improved to have correct rounding of results in rounding modes other than the default one (ie. FE_NEAREST) This commit fixes that, and adds tests for the change (note that there's still some rounding issues with the a conversion specifier in general in relatively rare cases (that is without non-default rounding modes) where I've left commented-out tests for anyone interested in improving it more
This commit is contained in:
parent
51c0f44d1c
commit
4d05060aac
2 changed files with 61 additions and 8 deletions
|
@ -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;
|
||||
|
|
|
@ -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…
Reference in a new issue