Hi, here's a patch to fix another problem with formatting long doubles in 
hexadecimal. I found a failing case with a denormalized value:

printf("0x2.0p-16385l :         %La\n", 0x2.0p-16385l);

Complete tests:

#include <stdio.h>
#include <stdlib.h>
#include <float.h>

int main(int argc, char **argv)
{
        puts(  " --- Long doubles ---\n");
        
        char buf[100];
        snprintf(buf, sizeof buf, "%La", 4.483595e-4949l);
        puts(buf);
        char *end;
        long double v = strtold(buf, &end);
        printf("%Le\n", v);
        
        if(v != 4.483595e-4949l)
                puts("Test failed for formatting 4.483595e-4949l.");
        else
                puts("Test succeeded for formatting 4.483595e-4949l.");
        
        printf("8.0l :                  %La\n", 8.0l);
        printf("1.5l :                  %La\n", 1.5l);
        printf("0.5l :                  %La\n", 0.5l);
        printf("2.0l :                  %La\n", 2.0l);
        printf("1.0l :                  %La\n", 1.0l);
        printf("0.0l :                  %La\n", 0.0l);
        printf("-8.0l :                 %La\n", -8.0l);
        printf("-1.5l :                 %La\n", -1.5l);
        printf("-0.5l :                 %La\n", -0.5l);
        printf("-2.0l :                 %La\n", -2.0l);
        printf("-1.0l :                 %La\n", -1.0l);
        printf("-0.0l :                 %La\n", -0.0l);
        printf("423.2323l :             %La\n", 423.2323l);
        printf("-423.2323l :            %La\n", -423.2323l);
        printf("LDBL_MAX :              %La\n", LDBL_MAX);
        printf("-LDBL_MAX :             %La\n", -LDBL_MAX);
        puts(  " [Denormalized]");
        printf("4.4836e-4949l :         %La\n", 4.4836e-4949l);
        printf("-4.4836e-4949l :        %La\n", -4.4836e-4949l);
        printf("4.4836e-4949l (.5) :    %.5La\n", 4.4836e-4949l);
        printf("-4.4836e-4949l (.5) :   %.5La\n", -4.4836e-4949l);
        printf("0x0.0030p+0l :          %La\n", 0x0.0030p+0l);
        printf("0x0.0040p+0l :          %La\n", 0x0.0040p+0l);
        printf("0x0.0040p+0l :          %40La\n", 0x0.0030p+0l);
        printf("0x0.0040p+0l :          %#40La\n", 0x0.0040p+0l);
        printf("0x0.0040p+0l :          %-40La\n", 0x0.0040p+0l);
        printf("0x0.0040p+0l :          %#-40La\n", 0x0.0040p+0l);
        printf("0x2.0p-16385l :         %La\n", 0x2.0p-16385l);
        puts(  " [Rounded]");
        printf("423.2323l (.10) :        %.10La\n", 423.2323l);
        printf("423.2323l (.20) :        %.20La\n", 423.2323l);
        printf("423.2323l (.1) :         %.1La\n", 423.2323l);
        printf("423.2323l (.0) :         %.0La\n", 423.2323l);
        printf("0.0l (.10) :             %.10La\n", 0.0l);
        printf("0.0l (.0) :              %.0La\n", 0.0l);
        printf("-423.2323l (.10) :       %.10La\n", -423.2323l);
        printf("-423.2323l (.20) :       %.20La\n", -423.2323l);
        printf("-423.2323l (.1) :        %.1La\n", -423.2323l);
        printf("-423.2323l (.0) :        %.0La\n", -423.2323l);
        printf("-0.0l (.10) :            %.10La\n", -0.0l);
        printf("-0.0l (.0) :             %.0La\n", -0.0l);
        printf("0xF.8p+0l (.0) :         %.0La\n", 0xF.8p+0l);
        printf("0xF.7p+0l (.0) :         %.0La\n", 0xF.7p+0l);
        printf("0xF.F8p+0l (.1) :        %.1La\n", 0xF.F8p+0l);
        printf("0xF.F7p+0l (.1) :        %.1La\n", 0xF.F7p+0l);
        printf("0x0.000000000000008p+0l (.1) : %.1La\n", 
0x0.000000000000008p+0l);
        printf("0x0.000000000000007p+0l (.1) : %.1La\n", 
0x0.000000000000007p+0l);
        printf("LDBL_MAX (.5) :          %.5La\n", LDBL_MAX);
        
        return EXIT_SUCCESS;
}
>From d65015f4d40617a6b82ae0bf3c8c6afe94b1b79a Mon Sep 17 00:00:00 2001
From: Patrick Northon <northon_patri...@yahoo.ca>
Date: Sun, 5 Sep 2021 17:31:17 -0400
Subject: [PATCH] Fix exponent when formatting long double in hexadecimal.

Some denormalized values were emited incorrectly. The leading digit will always assume to start at the 4th bit from the highest order bit in the mantissa and the exponent will be adjusted accordingly.
---
 mingw-w64-crt/stdio/mingw_pformat.c | 28 ++++++++++++----------------
 1 file changed, 12 insertions(+), 16 deletions(-)

diff --git a/mingw-w64-crt/stdio/mingw_pformat.c b/mingw-w64-crt/stdio/mingw_pformat.c
index 2e090c02f..1114cdbd9 100644
--- a/mingw-w64-crt/stdio/mingw_pformat.c
+++ b/mingw-w64-crt/stdio/mingw_pformat.c
@@ -2002,6 +2002,12 @@ void __pformat_emit_xfloat( __pformat_fpreg_t value, __pformat_t *stream )
   char buf[18 + 6], *p = buf;
   __pformat_intarg_t exponent; short exp_width = 2;
   
+  /* Reduce the exponent since the leading digit emited will start at 
+   * the 4th bit from the highest order bit instead, the later being 
+   * the leading digit of the floating point.
+   */
+  value.__pformat_fpreg_exponent -= 3;
+
   /* The mantissa field of the argument value representation can
    * accommodate at most 16 hexadecimal digits, of which one will
    * be placed before the radix point, leaving at most 15 digits
@@ -2045,7 +2051,7 @@ void __pformat_emit_xfloat( __pformat_fpreg_t value, __pformat_t *stream )
        * of this is equivalent to an increment of the exponent. We will
        * discard a whole digit to match glibc's behavior.
        */
-      value.__pformat_fpreg_exponent++;
+      value.__pformat_fpreg_exponent += 4;
       value.__pformat_fpreg_mantissa >>= 3;
     }
 
@@ -2086,20 +2092,6 @@ void __pformat_emit_xfloat( __pformat_fpreg_t value, __pformat_t *stream )
            */
           *p++ = '.';
         }
-
-        /* If the most significant hexadecimal digit of the encoded
-         * output value is greater than one, then the indicated value
-         * will appear too large, by an additional binary exponent
-         * corresponding to the number of higher order bit positions
-         * which it occupies...
-         */
-        while( value.__pformat_fpreg_mantissa > 1 )
-        {
-          /* so reduce the exponent value to compensate...
-           */
-          value.__pformat_fpreg_exponent--;
-          value.__pformat_fpreg_mantissa >>= 1;
-        }
       }
 
       else if( stream->precision > 0 )
@@ -2305,8 +2297,12 @@ void __pformat_xldouble( long double x, __pformat_t *stream )
 	{
 	  /* ...this mantissa represents a subnormal value.
 	   */
-	  z.__pformat_fpreg_exponent = -0x3FFF - 2;
+	  z.__pformat_fpreg_exponent = 1 - 0x3FFF;
 	}
+	else
+    /* Compensate for exponent being adjusted in `__pformat_emit_xfloat`.
+     */
+	  z.__pformat_fpreg_exponent = 3;
       }
       else
 	/* This argument represents a non-zero normal number;
-- 
2.33.0

_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to