Hopefully completely fix printf-family %a rounding (#1287)

The a conversion specifier to printf had some issues w.r.t. rounding, in
particular in edge cases w.r.t. "to nearest, ties to even" rounding (for
instance, "%.1a" with 0x1.78p+4 outputted 0x1.7p+4 instead of 0x1.8p+4).

This patch fixes this and adds several tests w.r.t ties to even rounding
This commit is contained in:
Gabriel Ravier 2024-09-15 21:11:27 +02:00 committed by GitHub
parent e65fe614b7
commit b55e4d61a9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 45 additions and 42 deletions

View file

@ -217,39 +217,37 @@ TEST(snprintf, testLongDoubleRounding) {
ASSERT_EQ(0, fesetround(previous_rounding));
}
void check_a_conversion_specifier_prec_1(const char *result_str, double value) {
char buf[30] = {0};
int i = snprintf(buf, sizeof(buf), "%.1a", value);
ASSERT_EQ(strlen(result_str), i);
ASSERT_STREQ(result_str, buf);
}
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_DOWNWARD));
check_a_conversion_specifier_prec_1("0x1.fp+4", 0x1.fffffp+4);
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);
check_a_conversion_specifier_prec_1("0x2.0p+4", 0x1.f8p+4);
ASSERT_EQ(0, fesetround(previous_rounding));
}
// This test currently fails because of rounding issues
// If that ever gets fixed, uncomment this
/*
// This test specifically checks that we round to even, accordingly to IEEE
// rules
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);
check_a_conversion_specifier_prec_1("0x1.8p+4", 0x1.7800000000001p+4);
check_a_conversion_specifier_prec_1("0x1.8p+4", 0x1.78p+4);
check_a_conversion_specifier_prec_1("0x1.8p+4", 0x1.88p+4);
check_a_conversion_specifier_prec_1("0x1.6p+4", 0x1.58p+4);
check_a_conversion_specifier_prec_1("0x1.6p+4", 0x1.68p+4);
check_a_conversion_specifier_prec_1("0x1.ap+4", 0x1.98p+4);
check_a_conversion_specifier_prec_1("0x1.ap+4", 0x1.a8p+4);
}
*/
TEST(snprintf, apostropheFlag) {
char buf[20];