Files
glibc/stdio-common/tst-printf-format-skeleton-double.c
T
Matt Turner 71e40f25cf stdio-common: Handle subnormal values in the printf format tests
The reference implementation used to verify the a and A conversions
assumed the value it was given was normal, splitting it into a
significand of the full width and an exponent.  That is not true below
the smallest normal value, where the exponent can go no lower and the
significand loses bits from the top instead, which is what makes the
leading hexadecimal digit of a subnormal come out as zero.  Given a
subnormal it would have produced a normalized result such as 0x1p-1070
where we print 0x0.000000000001p-1022.

Telling the two apart needs the minimum exponent for the type, which was
not among the data the test program supplies, so add it as a MINEXP
definition reported in a record of its own next to the working
precision. Then stop normalizing once that exponent is reached, and pad
the digits produced on the left, as there are no longer enough of them
to fill the field on their own.  The remaining conversions are
unaffected: they work from the value itself and never needed it
decomposed.

How far the exponent has to be shifted to sit after the significand
depends on the working precision, so hold MINEXP as reported and combine
the two only once a value is due to be converted, rather than requiring
the records to arrive in a particular order.  Where no MINEXP record
arrives the type has no subnormals and no clamping is applied.

None of the values iterated over were subnormal, so this could not be
observed.  Add DBL_TRUE_MIN and LDBL_TRUE_MIN to cover it, which also
exercises the smallest exponent with the remaining conversions.  How
many bits the leading hexadecimal digit holds varies with the type, one
for a 53 bit significand and four for a 64 bit one, so both are needed:
the wider case lands on a different exponent than the minimum for the
type, with LDBL_TRUE_MIN coming out as 0x0.000000000000001p-16385 rather
than at the p-16382 that the leading digit of a normal value would sit
at.  One sign is enough for either, as nothing in the sign handling
depends on the value being subnormal, and the records these produce are
among the most expensive in the test suite.

Tested on x86_64-linux-gnu, where all 672 results pass.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
2026-09-02 12:37:47 -05:00

37 lines
1.3 KiB
C

/* Test skeleton for formatted printf output for double conversions.
Copyright (C) 2024-2026 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <float.h>
#include <math.h>
#define MID_WIDTH 20
#define HUGE_WIDTH 320
/* Full-precision output runs to hundreds of digits here. */
#define TST_PRINTF_WIDE_TYPE 1
#define REF_FMT ".35e"
#define REF_VAL(v) (v)
#define PREC DBL_MANT_DIG
#define MINEXP DBL_MIN_EXP
typedef double type_t;
static const type_t vals[] =
{ -HUGE_VAL, -DBL_MAX, -DBL_MIN, -0.0, -NAN, NAN, 0, DBL_TRUE_MIN,
DBL_MIN, 99.9, DBL_MAX, HUGE_VAL };
static const char length[] = "";
#include "tst-printf-format-skeleton.c"