libstdc++: Fix up 20_util/to_chars/double.cc test for excess precision [PR110145]

Message ID ZIC7kEwyILqqnOht@tucnak
State Unresolved
Headers
Series libstdc++: Fix up 20_util/to_chars/double.cc test for excess precision [PR110145] |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Jakub Jelinek June 7, 2023, 5:17 p.m. UTC
  Hi!

This test apparently contains 3 problematic floating point constants,
1e126, 4.91e-6 and 5.547e-6.  These constants suffer from double rounding
when -fexcess-precision=standard evaluates double constants in the precision
of Intel extended 80-bit long double.
As written in the PR, e.g. the first one is
0x1.7a2ecc414a03f7ff6ca1cb527787b130a97d51e51202365p+418
in the precision of GCC's internal format, 80-bit long double has
63-bit precision, so the above constant rounded to long double is
0x1.7a2ecc414a03f800p+418L
(the least significant bit in the 0 before p isn't there already).
0x1.7a2ecc414a03f800p+418L rounded to IEEE double is
0x1.7a2ecc414a040p+418.
Now, if excess precision doesn't happen and we round the GCC's internal
format number directly to double, it is
0x1.7a2ecc414a03fp+418 and that is the number the test expects.
One can see it on x86-64 (where excess precision to long double doesn't
happen) where double(1e126L) != 1e126.
The other two constants suffer from the same problem.

The following patch tweaks the testcase, such that those problematic
constants are used only if FLT_EVAL_METHOD is 0 or 1 (i.e. when we have
guarantee the constants will be evaluated in double precision),
plus adds corresponding tests with hexadecimal constants which don't
suffer from this excess precision problem, they are exact in double
and long double can hold all double values.

Bootstrapped/regtested on x86_64-linux and i686-linux, additionally
tested on the latter with
make check RUNTESTFLAGS='--target_board=unix/-fexcess-precision=standard conformance.exp=to_chars/double.cc'
Ok for trunk?

2023-06-07  Jakub Jelinek  <jakub@redhat.com>

	PR libstdc++/110145
	* testsuite/20_util/to_chars/double.cc: Include <cfloat>.
	(double_to_chars_test_cases,
	double_scientific_precision_to_chars_test_cases_2,
	double_fixed_precision_to_chars_test_cases_2): #if out 1e126, 4.91e-6
	and 5.547e-6 tests if FLT_EVAL_METHOD is negative or larger than 1.
	Add unconditional tests with corresponding double constants
	0x1.7a2ecc414a03fp+418, 0x1.4981285e98e79p-18 and
	0x1.7440bbff418b9p-18.


	Jakub
  

Comments

Jonathan Wakely June 7, 2023, 5:25 p.m. UTC | #1
On Wed, 7 Jun 2023, 18:17 Jakub Jelinek via Libstdc++, <
libstdc++@gcc.gnu.org> wrote:

> Hi!
>
> This test apparently contains 3 problematic floating point constants,
> 1e126, 4.91e-6 and 5.547e-6.  These constants suffer from double rounding
> when -fexcess-precision=standard evaluates double constants in the
> precision
> of Intel extended 80-bit long double.
> As written in the PR, e.g. the first one is
> 0x1.7a2ecc414a03f7ff6ca1cb527787b130a97d51e51202365p+418
> in the precision of GCC's internal format, 80-bit long double has
> 63-bit precision, so the above constant rounded to long double is
> 0x1.7a2ecc414a03f800p+418L
> (the least significant bit in the 0 before p isn't there already).
> 0x1.7a2ecc414a03f800p+418L rounded to IEEE double is
> 0x1.7a2ecc414a040p+418.
> Now, if excess precision doesn't happen and we round the GCC's internal
> format number directly to double, it is
> 0x1.7a2ecc414a03fp+418 and that is the number the test expects.
> One can see it on x86-64 (where excess precision to long double doesn't
> happen) where double(1e126L) != 1e126.
> The other two constants suffer from the same problem.
>
> The following patch tweaks the testcase, such that those problematic
> constants are used only if FLT_EVAL_METHOD is 0 or 1 (i.e. when we have
> guarantee the constants will be evaluated in double precision),
> plus adds corresponding tests with hexadecimal constants which don't
> suffer from this excess precision problem, they are exact in double
> and long double can hold all double values.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, additionally
> tested on the latter with
> make check RUNTESTFLAGS='--target_board=unix/-fexcess-precision=standard
> conformance.exp=to_chars/double.cc'
> Ok for trunk?
>

Yes, OK.

Thanks for solving this puzzle!



> 2023-06-07  Jakub Jelinek  <jakub@redhat.com>
>
>         PR libstdc++/110145
>         * testsuite/20_util/to_chars/double.cc: Include <cfloat>.
>         (double_to_chars_test_cases,
>         double_scientific_precision_to_chars_test_cases_2,
>         double_fixed_precision_to_chars_test_cases_2): #if out 1e126,
> 4.91e-6
>         and 5.547e-6 tests if FLT_EVAL_METHOD is negative or larger than 1.
>         Add unconditional tests with corresponding double constants
>         0x1.7a2ecc414a03fp+418, 0x1.4981285e98e79p-18 and
>         0x1.7440bbff418b9p-18.
>
> --- libstdc++-v3/testsuite/20_util/to_chars/double.cc.jj        2022-11-03
> 22:16:08.542329555 +0100
> +++ libstdc++-v3/testsuite/20_util/to_chars/double.cc   2023-06-07
> 15:41:44.275604870 +0200
> @@ -40,6 +40,7 @@
>  #include <cstring>
>  #include <limits>
>  #include <optional>
> +#include <cfloat>
>
>  #include <testsuite_hooks.h>
>
> @@ -1968,9 +1969,19 @@ inline constexpr double_to_chars_testcas
>      {1e125, chars_format::fixed,
>
>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>          "5841365553228283904"},
> +#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
> +    // When long double is Intel extended and double constants are
> evaluated in precision of
> +    // long double, this value is initialized to double(1e126L), which is
> 0x1.7a2ecc414a040p+418 due to
> +    // double rounding of 0x1.7a2ecc414a03f7ff6p+418L first to
> 0x1.7a2ecc414a03f800p+418L and
> +    // then to 0x1.7a2ecc414a040p+418, while when double constants are
> evaluated in precision of
> +    // IEEE double, this is 0x1.7a2ecc414a03fp+418 which the test
> expects.  See PR110145.
>      {1e126, chars_format::fixed,
>
>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>          "58413655532282839040"},
> +#endif
> +    {0x1.7a2ecc414a03fp+418, chars_format::fixed,
> +
>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
> +       "58413655532282839040"},
>      {1e127, chars_format::fixed,
>
>  "9999999999999999549291066784979473595300225087383524118479625982517885450291174622154390152298057300868772"
>          "377386949310916067328"},
> @@ -2816,8 +2827,12 @@ inline constexpr double_to_chars_testcas
>      {0x1.a6c767640cd71p+879, chars_format::scientific,
> "6.6564021122018745e+264"},
>
>      // Incorrectly handled by dtoa_milo() (Grisu2), which doesn't achieve
> shortest round-trip.
> +#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
>      {4.91e-6, chars_format::scientific, "4.91e-06"},
>      {5.547e-6, chars_format::scientific, "5.547e-06"},
> +#endif
> +    {0x1.4981285e98e79p-18, chars_format::scientific, "4.91e-06"},
> +    {0x1.7440bbff418b9p-18, chars_format::scientific, "5.547e-06"},
>
>      // Test hexfloat corner cases.
>      {0x1.728p+0, chars_format::hex, "1.728p+0"}, // instead of "2.e5p-1"
> @@ -5537,10 +5552,16 @@ inline constexpr double_to_chars_testcas
>          "9."
>
>  "9999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005"
>          "841365553228283904e+124"},
> +#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
>      {1e+126, chars_format::scientific, 124,
>          "9."
>
>  "9999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005"
>          "841365553228283904e+125"},
> +#endif
> +    {0x1.7a2ecc414a03fp+418, chars_format::scientific, 124,
> +       "9."
> +
>  "9999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005"
> +       "841365553228283904e+125"},
>      {1e+127, chars_format::scientific, 126,
>          "9."
>
>  "9999999999999995492910667849794735953002250873835241184796259825178854502911746221543901522980573008687723"
> @@ -29579,9 +29600,14 @@ inline constexpr double_to_chars_testcas
>      {1e+125, chars_format::fixed, 0,
>
>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>          "5841365553228283904"},
> +#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
>      {1e+126, chars_format::fixed, 0,
>
>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>          "58413655532282839040"},
> +#endif
> +    {0x1.7a2ecc414a03fp+418, chars_format::fixed, 0,
> +
>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
> +       "58413655532282839040"},
>      {1e+127, chars_format::fixed, 0,
>
>  "9999999999999999549291066784979473595300225087383524118479625982517885450291174622154390152298057300868772"
>          "377386949310916067328"},
>
>         Jakub
>
>
  
Jonathan Wakely June 7, 2023, 7:59 p.m. UTC | #2
On Wed, 7 Jun 2023 at 18:26, Jonathan Wakely <jwakely.gcc@gmail.com> wrote:

>
>
> On Wed, 7 Jun 2023, 18:17 Jakub Jelinek via Libstdc++, <
> libstdc++@gcc.gnu.org> wrote:
>
>> Hi!
>>
>> This test apparently contains 3 problematic floating point constants,
>> 1e126, 4.91e-6 and 5.547e-6.  These constants suffer from double rounding
>> when -fexcess-precision=standard evaluates double constants in the
>> precision
>> of Intel extended 80-bit long double.
>> As written in the PR, e.g. the first one is
>> 0x1.7a2ecc414a03f7ff6ca1cb527787b130a97d51e51202365p+418
>> in the precision of GCC's internal format, 80-bit long double has
>> 63-bit precision, so the above constant rounded to long double is
>> 0x1.7a2ecc414a03f800p+418L
>> (the least significant bit in the 0 before p isn't there already).
>> 0x1.7a2ecc414a03f800p+418L rounded to IEEE double is
>> 0x1.7a2ecc414a040p+418.
>> Now, if excess precision doesn't happen and we round the GCC's internal
>> format number directly to double, it is
>> 0x1.7a2ecc414a03fp+418 and that is the number the test expects.
>> One can see it on x86-64 (where excess precision to long double doesn't
>> happen) where double(1e126L) != 1e126.
>> The other two constants suffer from the same problem.
>>
>> The following patch tweaks the testcase, such that those problematic
>> constants are used only if FLT_EVAL_METHOD is 0 or 1 (i.e. when we have
>> guarantee the constants will be evaluated in double precision),
>> plus adds corresponding tests with hexadecimal constants which don't
>> suffer from this excess precision problem, they are exact in double
>> and long double can hold all double values.
>>
>> Bootstrapped/regtested on x86_64-linux and i686-linux, additionally
>> tested on the latter with
>> make check RUNTESTFLAGS='--target_board=unix/-fexcess-precision=standard
>> conformance.exp=to_chars/double.cc'
>> Ok for trunk?
>>
>
> Yes, OK.
>
> Thanks for solving this puzzle!
>

I think this would be good for gcc-13, as that has the new
-fexcess-precision semantics for -std=c++NN too, right?


>
>
>
>> 2023-06-07  Jakub Jelinek  <jakub@redhat.com>
>>
>>         PR libstdc++/110145
>>         * testsuite/20_util/to_chars/double.cc: Include <cfloat>.
>>         (double_to_chars_test_cases,
>>         double_scientific_precision_to_chars_test_cases_2,
>>         double_fixed_precision_to_chars_test_cases_2): #if out 1e126,
>> 4.91e-6
>>         and 5.547e-6 tests if FLT_EVAL_METHOD is negative or larger than
>> 1.
>>         Add unconditional tests with corresponding double constants
>>         0x1.7a2ecc414a03fp+418, 0x1.4981285e98e79p-18 and
>>         0x1.7440bbff418b9p-18.
>>
>> --- libstdc++-v3/testsuite/20_util/to_chars/double.cc.jj
>> 2022-11-03 22:16:08.542329555 +0100
>> +++ libstdc++-v3/testsuite/20_util/to_chars/double.cc   2023-06-07
>> 15:41:44.275604870 +0200
>> @@ -40,6 +40,7 @@
>>  #include <cstring>
>>  #include <limits>
>>  #include <optional>
>> +#include <cfloat>
>>
>>  #include <testsuite_hooks.h>
>>
>> @@ -1968,9 +1969,19 @@ inline constexpr double_to_chars_testcas
>>      {1e125, chars_format::fixed,
>>
>>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>>          "5841365553228283904"},
>> +#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
>> +    // When long double is Intel extended and double constants are
>> evaluated in precision of
>> +    // long double, this value is initialized to double(1e126L), which
>> is 0x1.7a2ecc414a040p+418 due to
>> +    // double rounding of 0x1.7a2ecc414a03f7ff6p+418L first to
>> 0x1.7a2ecc414a03f800p+418L and
>> +    // then to 0x1.7a2ecc414a040p+418, while when double constants are
>> evaluated in precision of
>> +    // IEEE double, this is 0x1.7a2ecc414a03fp+418 which the test
>> expects.  See PR110145.
>>      {1e126, chars_format::fixed,
>>
>>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>>          "58413655532282839040"},
>> +#endif
>> +    {0x1.7a2ecc414a03fp+418, chars_format::fixed,
>> +
>>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>> +       "58413655532282839040"},
>>      {1e127, chars_format::fixed,
>>
>>  "9999999999999999549291066784979473595300225087383524118479625982517885450291174622154390152298057300868772"
>>          "377386949310916067328"},
>> @@ -2816,8 +2827,12 @@ inline constexpr double_to_chars_testcas
>>      {0x1.a6c767640cd71p+879, chars_format::scientific,
>> "6.6564021122018745e+264"},
>>
>>      // Incorrectly handled by dtoa_milo() (Grisu2), which doesn't
>> achieve shortest round-trip.
>> +#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
>>      {4.91e-6, chars_format::scientific, "4.91e-06"},
>>      {5.547e-6, chars_format::scientific, "5.547e-06"},
>> +#endif
>> +    {0x1.4981285e98e79p-18, chars_format::scientific, "4.91e-06"},
>> +    {0x1.7440bbff418b9p-18, chars_format::scientific, "5.547e-06"},
>>
>>      // Test hexfloat corner cases.
>>      {0x1.728p+0, chars_format::hex, "1.728p+0"}, // instead of "2.e5p-1"
>> @@ -5537,10 +5552,16 @@ inline constexpr double_to_chars_testcas
>>          "9."
>>
>>  "9999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005"
>>          "841365553228283904e+124"},
>> +#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
>>      {1e+126, chars_format::scientific, 124,
>>          "9."
>>
>>  "9999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005"
>>          "841365553228283904e+125"},
>> +#endif
>> +    {0x1.7a2ecc414a03fp+418, chars_format::scientific, 124,
>> +       "9."
>> +
>>  "9999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005"
>> +       "841365553228283904e+125"},
>>      {1e+127, chars_format::scientific, 126,
>>          "9."
>>
>>  "9999999999999995492910667849794735953002250873835241184796259825178854502911746221543901522980573008687723"
>> @@ -29579,9 +29600,14 @@ inline constexpr double_to_chars_testcas
>>      {1e+125, chars_format::fixed, 0,
>>
>>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>>          "5841365553228283904"},
>> +#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
>>      {1e+126, chars_format::fixed, 0,
>>
>>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>>          "58413655532282839040"},
>> +#endif
>> +    {0x1.7a2ecc414a03fp+418, chars_format::fixed, 0,
>> +
>>  "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
>> +       "58413655532282839040"},
>>      {1e+127, chars_format::fixed, 0,
>>
>>  "9999999999999999549291066784979473595300225087383524118479625982517885450291174622154390152298057300868772"
>>          "377386949310916067328"},
>>
>>         Jakub
>>
>>
  

Patch

--- libstdc++-v3/testsuite/20_util/to_chars/double.cc.jj	2022-11-03 22:16:08.542329555 +0100
+++ libstdc++-v3/testsuite/20_util/to_chars/double.cc	2023-06-07 15:41:44.275604870 +0200
@@ -40,6 +40,7 @@ 
 #include <cstring>
 #include <limits>
 #include <optional>
+#include <cfloat>
 
 #include <testsuite_hooks.h>
 
@@ -1968,9 +1969,19 @@  inline constexpr double_to_chars_testcas
     {1e125, chars_format::fixed,
         "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
         "5841365553228283904"},
+#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
+    // When long double is Intel extended and double constants are evaluated in precision of
+    // long double, this value is initialized to double(1e126L), which is 0x1.7a2ecc414a040p+418 due to
+    // double rounding of 0x1.7a2ecc414a03f7ff6p+418L first to 0x1.7a2ecc414a03f800p+418L and
+    // then to 0x1.7a2ecc414a040p+418, while when double constants are evaluated in precision of
+    // IEEE double, this is 0x1.7a2ecc414a03fp+418 which the test expects.  See PR110145.
     {1e126, chars_format::fixed,
         "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
         "58413655532282839040"},
+#endif
+    {0x1.7a2ecc414a03fp+418, chars_format::fixed,
+	"9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
+	"58413655532282839040"},
     {1e127, chars_format::fixed,
         "9999999999999999549291066784979473595300225087383524118479625982517885450291174622154390152298057300868772"
         "377386949310916067328"},
@@ -2816,8 +2827,12 @@  inline constexpr double_to_chars_testcas
     {0x1.a6c767640cd71p+879, chars_format::scientific, "6.6564021122018745e+264"},
 
     // Incorrectly handled by dtoa_milo() (Grisu2), which doesn't achieve shortest round-trip.
+#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
     {4.91e-6, chars_format::scientific, "4.91e-06"},
     {5.547e-6, chars_format::scientific, "5.547e-06"},
+#endif
+    {0x1.4981285e98e79p-18, chars_format::scientific, "4.91e-06"},
+    {0x1.7440bbff418b9p-18, chars_format::scientific, "5.547e-06"},
 
     // Test hexfloat corner cases.
     {0x1.728p+0, chars_format::hex, "1.728p+0"}, // instead of "2.e5p-1"
@@ -5537,10 +5552,16 @@  inline constexpr double_to_chars_testcas
         "9."
         "9999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005"
         "841365553228283904e+124"},
+#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
     {1e+126, chars_format::scientific, 124,
         "9."
         "9999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005"
         "841365553228283904e+125"},
+#endif
+    {0x1.7a2ecc414a03fp+418, chars_format::scientific, 124,
+	"9."
+	"9999999999999992486776161899288204254467086983483846143922597222529419997579302660316349376281765375153005"
+	"841365553228283904e+125"},
     {1e+127, chars_format::scientific, 126,
         "9."
         "9999999999999995492910667849794735953002250873835241184796259825178854502911746221543901522980573008687723"
@@ -29579,9 +29600,14 @@  inline constexpr double_to_chars_testcas
     {1e+125, chars_format::fixed, 0,
         "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
         "5841365553228283904"},
+#if FLT_EVAL_METHOD >= 0 && FLT_EVAL_METHOD <= 1
     {1e+126, chars_format::fixed, 0,
         "9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
         "58413655532282839040"},
+#endif
+    {0x1.7a2ecc414a03fp+418, chars_format::fixed, 0,
+	"9999999999999999248677616189928820425446708698348384614392259722252941999757930266031634937628176537515300"
+	"58413655532282839040"},
     {1e+127, chars_format::fixed, 0,
         "9999999999999999549291066784979473595300225087383524118479625982517885450291174622154390152298057300868772"
         "377386949310916067328"},