public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
From: Patrick Palka <ppalka@redhat.com>
To: Jonathan Wakely <jwakely@redhat.com>
Cc: Jakub Jelinek <jakub@redhat.com>,
	Patrick Palka <ppalka@redhat.com>,
	 gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org
Subject: Re: [PATCH] libstdc++: Shortest denormal hex std::to_chars
Date: Tue, 1 Nov 2022 09:46:11 -0400 (EDT)	[thread overview]
Message-ID: <06028fc5-e292-e0df-cc39-bdaa22f06b11@idea> (raw)
In-Reply-To: <CACb0b4mpzqrR7Z_Aouuf93U_TrLSGuPE=LP05-rTCrxhxxOfhQ@mail.gmail.com>

On Tue, 1 Nov 2022, Jonathan Wakely wrote:

> On Tue, 1 Nov 2022 at 12:18, Jakub Jelinek <jakub@redhat.com> wrote:
> >
> > On Fri, Oct 28, 2022 at 12:52:44PM -0400, Patrick Palka wrote:
> > > > The following patch on top of
> > > > https://gcc.gnu.org/pipermail/libstdc++/2022-October/054849.html
> > > > adds std::{,b}float16_t support for std::to_chars.
> > > > When precision is specified (or for std::bfloat16_t for hex mode even if not),
> > > > I believe we can just use the std::to_chars float (when float is mode
> > > > compatible with std::float32_t) overloads, both formats are proper subsets
> > > > of std::float32_t.
> > > > Unfortunately when precision is not specified and we are supposed to emit
> > > > shortest string, the std::{,b}float16_t strings are usually much shorter.
> > > > E.g. 1.e7p-14f16 shortest fixed representation is
> > > > 0.0001161 and shortest scientific representation is
> > > > 1.161e-04 while 1.e7p-14f32 (same number promoted to std::float32_t)
> > > > 0.00011610985 and
> > > > 1.1610985e-04.
> > > > Similarly for 1.38p-112bf16,
> > > > 0.000000000000000000000000000000000235
> > > > 2.35e-34 vs. 1.38p-112f32
> > > > 0.00000000000000000000000000000000023472271
> > > > 2.3472271e-34
> > > > For std::float16_t there are differences even in the shortest hex, say:
> > > > 0.01p-14 vs. 1p-22
> > > > but only for denormal std::float16_t values (where all std::float16_t
> > > > denormals converted to std::float32_t are normal), __FLT16_MIN__ and
> > > > everything larger in absolute value than that is the same.  Unless
> > > > that is a bug and we should try to discover shorter representations
> > > > even for denormals...
> > >
> > > IIRC for hex formatting of denormals I opted to be consistent with how
> > > glibc printf formats them, instead of outputting the truly shortest
> > > form.
> > >
> > > I wouldn't be against using the float32 overloads even for shortest hex
> > > formatting of float16.  The output is shorter but equivalent so it
> > > shouldn't cause any problems.
> >
> > The following patch changes the behavior of the shortest hex denormals,
> > such that they are printed like normals (so for has_implicit_leading_bit
> > with 1p-149 instead of 0.000002p-126 etc., otherwise (Intel extended)
> > with the leading digit before dot being [89abcdef]).  I think for all the
> > supported format it is never longer, it can be equal length e.g. for
> > 0.fffffep-126 vs. 1.fffffcp-127 but fortunately no largest subnormal
> > in any format has the unbiased exponent like -9, -99, -999, -9999 because
> > then it would be longer and often it is shorter, sometimes much shorter.
> >
> > For the cases with precision it keeps the handling as is.
> >
> > While for !has_implicit_leading_bit we for normals or with this patch
> > even denormals have really shortest representation, for other formats
> > we sometimes do not, but this patch doesn't deal with that (we
> > always use 1.NNN while we could use 1.NNN up to f.NNN and by that shortening
> > by the last hexit if the last hexit doesn't have least significant bit set
> > and unbiased exponent is not -9, -99, -999 or -9999.
> >
> > Tested on x86_64-linux (on top of the 3 to/from_chars {,b}float16_t
> > patches).
> 
> This looks good to me. Please give Patrick a chance to comment, but
> it's approved for trunk unless he objects. Thanks!

LGTM.  This'll mean the output of to_chars(denormal, hex, precision)
will no longer be based on the shortest form to_chars(denormal, hex)
which slightly bothers me, but doesn't seem to be nonconforming either.

> 
> 
> >
> > 2022-11-01  Jakub Jelinek  <jakub@redhat.com>
> >
> >         * src/c++17/floating_to_chars.cc (__floating_to_chars_hex): Drop const
> >         from unbiased_exponent.  Canonicalize denormals such that they have
> >         the leading bit set by shifting effective mantissa up and decreasing
> >         unbiased_exponent.
> >         (__floating_to_chars_shortest): Don't instantiate
> >         __floating_to_chars_hex for float16_t either and use float instead.
> >         * testsuite/20_util/to_chars/float.cc (float_to_chars_test_cases):
> >         Adjust testcases for shortest hex denormals.
> >         * testsuite/20_util/to_chars/double.cc (double_to_chars_test_cases):
> >         Likewise.
> >
> > --- libstdc++-v3/src/c++17/floating_to_chars.cc.jj      2022-10-31 22:20:35.881121902 +0100
> > +++ libstdc++-v3/src/c++17/floating_to_chars.cc 2022-11-01 12:16:14.352652455 +0100
> > @@ -844,9 +844,9 @@ template<typename T>
> >      const bool is_normal_number = (biased_exponent != 0);
> >
> >      // Calculate the unbiased exponent.
> > -    const int32_t unbiased_exponent = (is_normal_number
> > -                                      ? biased_exponent - exponent_bias
> > -                                      : 1 - exponent_bias);
> > +    int32_t unbiased_exponent = (is_normal_number
> > +                                ? biased_exponent - exponent_bias
> > +                                : 1 - exponent_bias);
> >
> >      // Shift the mantissa so that its bitwidth is a multiple of 4.
> >      constexpr unsigned rounded_mantissa_bits = (mantissa_bits + 3) / 4 * 4;
> > @@ -863,6 +863,16 @@ template<typename T>
> >           __glibcxx_assert(effective_mantissa & (mantissa_t{1} << (mantissa_bits
> >                                                                    - 1u)));
> >        }
> > +    else if (!precision.has_value() && effective_mantissa)
> > +      {
> > +       // 1.8p-23 is shorter than 0.00cp-14, so if precision is
> > +       // omitted, try to canonicalize denormals such that they
> > +       // have the leading bit set.
> > +       int width = __bit_width(effective_mantissa);
> > +       int shift = rounded_mantissa_bits - width + has_implicit_leading_bit;
> > +       unbiased_exponent -= shift;
> > +       effective_mantissa <<= shift;
> > +      }
> >
> >      // Compute the shortest precision needed to print this value exactly,
> >      // disregarding trailing zeros.
> > @@ -1061,7 +1071,10 @@ template<typename T>
> >         // std::bfloat16_t has the same exponent range as std::float32_t
> >         // and so we can avoid instantiation of __floating_to_chars_hex
> >         // for bfloat16_t.  Shortest hex will be the same as for float.
> > -       if constexpr (is_same_v<T, floating_type_bfloat16_t>)
> > +       // When we print shortest form even for denormals, we can do it
> > +       // for std::float16_t as well.
> > +       if constexpr (is_same_v<T, floating_type_float16_t>
> > +                     || is_same_v<T, floating_type_bfloat16_t>)
> >           return __floating_to_chars_hex(first, last, value.x, nullopt);
> >         else
> >           return __floating_to_chars_hex(first, last, value, nullopt);
> > --- libstdc++-v3/testsuite/20_util/to_chars/float.cc.jj 2022-01-11 22:31:41.605755528 +0100
> > +++ libstdc++-v3/testsuite/20_util/to_chars/float.cc    2022-11-01 12:34:21.370882443 +0100
> > @@ -521,8 +521,8 @@ inline constexpr float_to_chars_testcase
> >
> >      // Test hexfloat corner cases.
> >      {0x1.728p+0f, chars_format::hex, "1.728p+0"}, // instead of "2.e5p-1"
> > -    {0x0.000002p-126f, chars_format::hex, "0.000002p-126"}, // instead of "1p-149", min subnormal
> > -    {0x0.fffffep-126f, chars_format::hex, "0.fffffep-126"}, // max subnormal
> > +    {0x0.000002p-126f, chars_format::hex, "1p-149"}, // min subnormal
> > +    {0x0.fffffep-126f, chars_format::hex, "1.fffffcp-127"}, // max subnormal
> >      {0x1p-126f, chars_format::hex, "1p-126"}, // min normal
> >      {0x1.fffffep+127f, chars_format::hex, "1.fffffep+127"}, // max normal
> >
> > --- libstdc++-v3/testsuite/20_util/to_chars/double.cc.jj        2022-01-11 22:31:41.604755542 +0100
> > +++ libstdc++-v3/testsuite/20_util/to_chars/double.cc   2022-11-01 12:42:39.753112522 +0100
> > @@ -2821,8 +2821,8 @@ inline constexpr double_to_chars_testcas
> >
> >      // Test hexfloat corner cases.
> >      {0x1.728p+0, chars_format::hex, "1.728p+0"}, // instead of "2.e5p-1"
> > -    {0x0.0000000000001p-1022, chars_format::hex, "0.0000000000001p-1022"}, // instead of "1p-1074", min subnormal
> > -    {0x0.fffffffffffffp-1022, chars_format::hex, "0.fffffffffffffp-1022"}, // max subnormal
> > +    {0x0.0000000000001p-1022, chars_format::hex, "1p-1074"}, // min subnormal
> > +    {0x0.fffffffffffffp-1022, chars_format::hex, "1.ffffffffffffep-1023"}, // max subnormal
> >      {0x1p-1022, chars_format::hex, "1p-1022"}, // min normal
> >      {0x1.fffffffffffffp+1023, chars_format::hex, "1.fffffffffffffp+1023"}, // max normal
> >
> >
> >         Jakub
> >
> 
> 


  reply	other threads:[~2022-11-01 13:46 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-10-27  7:59 [PATCH] libstdc++: std::to_chars std::{,b}float16_t support Jakub Jelinek
2022-10-28 16:52 ` Patrick Palka
2022-10-28 17:16   ` Jakub Jelinek
2022-11-01 12:18   ` [PATCH] libstdc++: Shortest denormal hex std::to_chars Jakub Jelinek
2022-11-01 12:24     ` Jonathan Wakely
2022-11-01 13:46       ` Patrick Palka [this message]
2022-11-01 12:22 ` [PATCH] libstdc++: std::to_chars std::{,b}float16_t support Jonathan Wakely

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=06028fc5-e292-e0df-cc39-bdaa22f06b11@idea \
    --to=ppalka@redhat.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jakub@redhat.com \
    --cc=jwakely@redhat.com \
    --cc=libstdc++@gcc.gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).