mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-01 15:30:29 +00:00
Partially fix printf hex float numbers/%a rounding
Hexadecimal printing of floating-point numbers on cosmopolitan (that is, using the a conversion specifier) currently does not correctly round the result in any rounding mode except for the default one (i.e. FE_NEAREST) This commit fixes this, 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), but this author gave up on fixing them after they tried to read the floating point formatting code, and wounded up almost more confused than before).
This commit is contained in:
parent
cceddd21b2
commit
64521d33f1
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…
Add table
Add a link
Reference in a new issue