1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-07-29 11:41:21 +03:00

Make printf respect the rounding mode for hex output (bug 5044).

This commit is contained in:
Joseph Myers
2012-09-24 15:38:21 +00:00
parent eaf6f205ff
commit a9f8e53a5b
4 changed files with 170 additions and 19 deletions

View File

@ -1,3 +1,16 @@
2012-09-24 Joseph Myers <joseph@codesourcery.com>
[BZ #5044]
* stdio-common/printf_fphex.c: Include <stdbool.h> and
<rounding-mode.h>.
(__printf_fphex): Determine rounding using get_rounding_mode and
round_away.
* stdio-common/tst-printf-round.c (struct hex_test): New
structure.
(hex_tests): New variable.
(test_hex_in_one_mode): New function.
(do_test): Also run tests for hex float output.
2012-09-21 Joseph Myers <joseph@codesourcery.com> 2012-09-21 Joseph Myers <joseph@codesourcery.com>
* libio/iopopen.c [_IO_HAVE_SYS_WAIT]: Make code unconditional. * libio/iopopen.c [_IO_HAVE_SYS_WAIT]: Make code unconditional.

12
NEWS
View File

@ -9,12 +9,12 @@ Version 2.17
* The following bugs are resolved with this release: * The following bugs are resolved with this release:
1349, 3479, 5400, 6778, 6808, 9685, 9914, 10014, 10038, 11607, 13412, 1349, 3479, 5044, 5400, 6778, 6808, 9685, 9914, 10014, 10038, 11607,
13542, 13717, 13696, 13939, 13966, 14042, 14090, 14166, 14150, 14151, 13412, 13542, 13717, 13696, 13939, 13966, 14042, 14090, 14166, 14150,
14154, 14157, 14166, 14173, 14195, 14237, 14252, 14283, 14298, 14303, 14151, 14154, 14157, 14166, 14173, 14195, 14237, 14252, 14283, 14298,
14307, 14328, 14331, 14336, 14337, 14347, 14349, 14459, 14476, 14505, 14303, 14307, 14328, 14331, 14336, 14337, 14347, 14349, 14459, 14476,
14510, 14516, 14518, 14519, 14532, 14538, 14544, 14545, 14576, 14579, 14505, 14510, 14516, 14518, 14519, 14532, 14538, 14544, 14545, 14576,
14583, 14587. 14579, 14583, 14587.
* Support for STT_GNU_IFUNC symbols added for s390 and s390x. * Support for STT_GNU_IFUNC symbols added for s390 and s390x.
Optimized versions of memcpy, memset, and memcmp added for System z10 and Optimized versions of memcpy, memset, and memcmp added for System z10 and

View File

@ -28,6 +28,8 @@
#include <_itoa.h> #include <_itoa.h>
#include <_itowa.h> #include <_itowa.h>
#include <locale/localeinfo.h> #include <locale/localeinfo.h>
#include <stdbool.h>
#include <rounding-mode.h>
/* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */ /* #define NDEBUG 1*/ /* Undefine this for debugging assertions. */
#include <assert.h> #include <assert.h>
@ -343,21 +345,33 @@ __printf_fphex (FILE *fp,
--numend; --numend;
} }
bool do_round_away = false;
if (precision != -1 && precision < numend - numstr)
{
char last_digit = precision > 0 ? numstr[precision - 1] : leading;
char next_digit = numstr[precision];
int last_digit_value = (last_digit >= 'A' && last_digit <= 'F'
? last_digit - 'A' + 10
: (last_digit >= 'a' && last_digit <= 'f'
? last_digit - 'a' + 10
: last_digit - '0'));
int next_digit_value = (next_digit >= 'A' && next_digit <= 'F'
? next_digit - 'A' + 10
: (next_digit >= 'a' && next_digit <= 'f'
? next_digit - 'a' + 10
: next_digit - '0'));
bool more_bits = ((next_digit_value & 7) != 0
|| precision + 1 < numend - numstr);
int rounding_mode = get_rounding_mode ();
do_round_away = round_away (negative, last_digit_value & 1,
next_digit_value >= 8, more_bits,
rounding_mode);
}
if (precision == -1) if (precision == -1)
precision = numend - numstr; precision = numend - numstr;
else if (precision < numend - numstr else if (do_round_away)
&& (numstr[precision] > '8'
|| (('A' < '0' || 'a' < '0')
&& numstr[precision] < '0')
|| (numstr[precision] == '8'
&& (precision + 1 < numend - numstr
/* Round to even. */
|| (precision > 0
&& ((numstr[precision - 1] & 1)
^ (isdigit (numstr[precision - 1]) == 0)))
|| (precision == 0
&& ((leading & 1)
^ (isdigit (leading) == 0)))))))
{ {
/* Round up. */ /* Round up. */
int cnt = precision; int cnt = precision;

View File

@ -68,6 +68,99 @@ test_dec_in_one_mode (double d, const char *fmt, const char *expected,
} }
} }
struct hex_test
{
double d;
const char *fmt;
const char *rd[4], *rn[4], *rz[4], *ru[4];
};
static const struct hex_test hex_tests[] =
{
{
0x1.fffffp+4, "%.1a",
{ "0x1.fp+4", "0x3.fp+3", "0x7.fp+2", "0xf.fp+1" },
{ "0x2.0p+4", "0x4.0p+3", "0x8.0p+2", "0x1.0p+5" },
{ "0x1.fp+4", "0x3.fp+3", "0x7.fp+2", "0xf.fp+1" },
{ "0x2.0p+4", "0x4.0p+3", "0x8.0p+2", "0x1.0p+5" }
},
{
-0x1.fffffp+4, "%.1a",
{ "-0x2.0p+4", "-0x4.0p+3", "-0x8.0p+2", "-0x1.0p+5" },
{ "-0x2.0p+4", "-0x4.0p+3", "-0x8.0p+2", "-0x1.0p+5" },
{ "-0x1.fp+4", "-0x3.fp+3", "-0x7.fp+2", "-0xf.fp+1" },
{ "-0x1.fp+4", "-0x3.fp+3", "-0x7.fp+2", "-0xf.fp+1" }
},
{
0x1.88p+4, "%.1a",
{ "0x1.8p+4", "0x3.1p+3", "0x6.2p+2", "0xc.4p+1" },
{ "0x1.8p+4", "0x3.1p+3", "0x6.2p+2", "0xc.4p+1" },
{ "0x1.8p+4", "0x3.1p+3", "0x6.2p+2", "0xc.4p+1" },
{ "0x1.9p+4", "0x3.1p+3", "0x6.2p+2", "0xc.4p+1" }
},
{
-0x1.88p+4, "%.1a",
{ "-0x1.9p+4", "-0x3.1p+3", "-0x6.2p+2", "-0xc.4p+1" },
{ "-0x1.8p+4", "-0x3.1p+3", "-0x6.2p+2", "-0xc.4p+1" },
{ "-0x1.8p+4", "-0x3.1p+3", "-0x6.2p+2", "-0xc.4p+1" },
{ "-0x1.8p+4", "-0x3.1p+3", "-0x6.2p+2", "-0xc.4p+1" }
},
{
0x1.78p+4, "%.1a",
{ "0x1.7p+4", "0x2.fp+3", "0x5.ep+2", "0xb.cp+1" },
{ "0x1.8p+4", "0x2.fp+3", "0x5.ep+2", "0xb.cp+1" },
{ "0x1.7p+4", "0x2.fp+3", "0x5.ep+2", "0xb.cp+1" },
{ "0x1.8p+4", "0x2.fp+3", "0x5.ep+2", "0xb.cp+1" }
},
{
-0x1.78p+4, "%.1a",
{ "-0x1.8p+4", "-0x2.fp+3", "-0x5.ep+2", "-0xb.cp+1" },
{ "-0x1.8p+4", "-0x2.fp+3", "-0x5.ep+2", "-0xb.cp+1" },
{ "-0x1.7p+4", "-0x2.fp+3", "-0x5.ep+2", "-0xb.cp+1" },
{ "-0x1.7p+4", "-0x2.fp+3", "-0x5.ep+2", "-0xb.cp+1" }
},
{
64.0 / 3.0, "%.1a",
{ "0x1.5p+4", "0x2.ap+3", "0x5.5p+2", "0xa.ap+1" },
{ "0x1.5p+4", "0x2.bp+3", "0x5.5p+2", "0xa.bp+1" },
{ "0x1.5p+4", "0x2.ap+3", "0x5.5p+2", "0xa.ap+1" },
{ "0x1.6p+4", "0x2.bp+3", "0x5.6p+2", "0xa.bp+1" }
},
{
-64.0 / 3.0, "%.1a",
{ "-0x1.6p+4", "-0x2.bp+3", "-0x5.6p+2", "-0xa.bp+1" },
{ "-0x1.5p+4", "-0x2.bp+3", "-0x5.5p+2", "-0xa.bp+1" },
{ "-0x1.5p+4", "-0x2.ap+3", "-0x5.5p+2", "-0xa.ap+1" },
{ "-0x1.5p+4", "-0x2.ap+3", "-0x5.5p+2", "-0xa.ap+1" }
},
};
static int
test_hex_in_one_mode (double d, const char *fmt, const char *expected[4],
const char *mode_name)
{
char buf[100];
int ret = snprintf (buf, sizeof buf, fmt, d);
if (ret <= 0 || ret >= (int) sizeof buf)
{
printf ("snprintf for %a returned %d\n", d, ret);
return 1;
}
if (strcmp (buf, expected[0]) == 0
|| strcmp (buf, expected[1]) == 0
|| strcmp (buf, expected[2]) == 0
|| strcmp (buf, expected[3]) == 0)
return 0;
else
{
printf ("snprintf (\"%s\", %a) returned \"%s\" not "
"\"%s\" or \"%s\" or \"%s\" or \"%s\" (%s)\n",
fmt, d, buf, expected[0], expected[1], expected[2], expected[3],
mode_name);
return 1;
}
}
static int static int
do_test (void) do_test (void)
{ {
@ -103,6 +196,37 @@ do_test (void)
} }
#endif #endif
} }
for (size_t i = 0; i < sizeof (hex_tests) / sizeof (hex_tests[0]); i++)
{
result |= test_hex_in_one_mode (hex_tests[i].d, hex_tests[i].fmt,
hex_tests[i].rn, "default rounding mode");
#ifdef FE_DOWNWARD
if (!fesetround (FE_DOWNWARD))
{
result |= test_hex_in_one_mode (hex_tests[i].d, hex_tests[i].fmt,
hex_tests[i].rd, "FE_DOWNWARD");
fesetround (save_round_mode);
}
#endif
#ifdef FE_TOWARDZERO
if (!fesetround (FE_TOWARDZERO))
{
result |= test_hex_in_one_mode (hex_tests[i].d, hex_tests[i].fmt,
hex_tests[i].rz, "FE_TOWARDZERO");
fesetround (save_round_mode);
}
#endif
#ifdef FE_UPWARD
if (!fesetround (FE_UPWARD))
{
result |= test_hex_in_one_mode (hex_tests[i].d, hex_tests[i].fmt,
hex_tests[i].ru, "FE_UPWARD");
fesetround (save_round_mode);
}
#endif
}
return result; return result;
} }