This is the mail archive of the libc-hacker@sourceware.org mailing list for the glibc project.

Note that libc-hacker is a closed list. You may look at the archives of this list, but subscription and posting are not open.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix *printf %La with IBM long double format


Hi!

As the attached testcase shows, printf_fphex for ldbl-128ibm
has a bunch of issues when the lower double is denormal or has exponent 1.
E.g. the implicit mantissa bit needs to be also set for exponent 1,
the difference between exponents might be smaller than 53 (when the
smaller double is denormal and the bigger double has exponent less than
53, etc.

I've also included the unrelated workaround for test-misc.c failures
- the tests from 2007-05-03 aren't really testable on ppc/ppc64.

2007-06-04  Jakub Jelinek  <jakub@redhat.com>

	* sysdeps/ieee754/ldbl-128ibm/printf_fphex.c
	(PRINT_FPHEX_LONG_DOUBLE): Fix printing numbers where lower double
	is non-zero, but smaller than 2 * __DBL_MIN__.
	* stdio-common/tst-sprintf2.c: New test.
	* stdio-common/Makefile (tests): Add tst-sprintf2.

	* math/test-misc.c (main): Don't run last batch of tests with
	IBM long double format.

--- libc/sysdeps/ieee754/ldbl-128ibm/printf_fphex.c.jj	2006-01-28 01:07:25.000000000 +0100
+++ libc/sysdeps/ieee754/ldbl-128ibm/printf_fphex.c	2007-06-04 14:02:12.000000000 +0200
@@ -1,5 +1,5 @@
 /* Print floating point number in hexadecimal notation according to ISO C99.
-   Copyright (C) 1997,1998,1999,2000,2001,2002,2004,2006
+   Copyright (C) 1997,1998,1999,2000,2001,2002,2004,2006,2007
 	Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
@@ -35,21 +35,24 @@ do {									      \
 									      \
       lo = ((long long)eldbl.ieee.mantissa2 << 32) | eldbl.ieee.mantissa3;    \
       hi = ((long long)eldbl.ieee.mantissa0 << 32) | eldbl.ieee.mantissa1;    \
-   /* If the lower double is not a denomal or zero then set the hidden	      \
-      53rd bit.  */							      \
-      if (eldbl.ieee.exponent2 > 0x001)					      \
-	{								      \
-	  lo |= (1ULL << 52);						      \
-	  lo = lo << 7; /* pre-shift lo to match ieee854.  */		      \
-	  /* The lower double is normalized separately from the upper.  We    \
-	     may need to adjust the lower manitissa to reflect this.  */      \
-	  ediff = eldbl.ieee.exponent - eldbl.ieee.exponent2;		      \
-	  if (ediff > 53)						      \
-	    lo = lo >> (ediff-53);					      \
-	}								      \
-  									      \
-      if ((eldbl.ieee.negative != eldbl.ieee.negative2)			      \
-	  && ((eldbl.ieee.exponent2 != 0) && (lo != 0L)))		      \
+      lo <<= 7; /* pre-shift lo to match ieee854.  */			      \
+      /* If the lower double is not a denomal or zero then set the hidden     \
+	 53rd bit.  */							      \
+      if (eldbl.ieee.exponent2 != 0)					      \
+	lo |= (1ULL << (52 + 7));					      \
+      else								      \
+	lo <<= 1;							      \
+      /* The lower double is normalized separately from the upper.  We	      \
+	 may need to adjust the lower manitissa to reflect this.  */	      \
+      ediff = eldbl.ieee.exponent - eldbl.ieee.exponent2;		      \
+      if (ediff > 53 + 63)						      \
+	lo = 0;								      \
+      else if (ediff > 53)						      \
+	lo = lo >> (ediff - 53);					      \
+      else if (eldbl.ieee.exponent2 == 0 && ediff < 53)			      \
+	lo = lo << (53 - ediff);					      \
+      if (eldbl.ieee.negative != eldbl.ieee.negative2			      \
+	  && (eldbl.ieee.exponent2 != 0 || lo != 0L))			      \
 	{								      \
 	  lo = (1ULL << 60) - lo;					      \
 	  if (hi == 0L)							      \
--- libc/stdio-common/Makefile.jj	2007-03-19 17:43:12.000000000 +0100
+++ libc/stdio-common/Makefile	2007-06-04 14:05:02.000000000 +0200
@@ -54,7 +54,7 @@ tests := tstscanf test_rdwr test-popen t
 	 tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \
 	 tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \
 	 tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \
-	 tst-fwrite bug16 bug17 tst-swscanf
+	 tst-fwrite bug16 bug17 tst-swscanf tst-sprintf2
 
 test-srcs = tst-unbputc tst-printf
 
--- libc/stdio-common/tst-sprintf2.c.jj	2007-06-04 14:03:18.000000000 +0200
+++ libc/stdio-common/tst-sprintf2.c	2007-06-04 14:04:35.000000000 +0200
@@ -0,0 +1,59 @@
+#include <float.h>
+#include <math.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+  volatile union { long double l; long long x[2]; } u;
+  char buf[64];
+  int result = 0;
+
+#define TEST(val) \
+  do									   \
+    {									   \
+      u.l = (val);							   \
+      snprintf (buf, sizeof buf, "%LaL", u.l);				   \
+      if (strcmp (buf, #val) != 0)					   \
+	{								   \
+	  printf ("Error on line %d: %s != %s\n", __LINE__, buf, #val);	   \
+	  result = 1;							   \
+	}								   \
+      /* printf ("%s %La %016Lx %016Lx\n", #val, u.l, u.x[0], u.x[1]); */  \
+    }									   \
+  while (0)
+
+#if LDBL_MANT_DIG >= 106
+# if LDBL_MANT_DIG == 106
+  TEST (0x0.ffffffffffffp-1022L);
+  TEST (0x0.ffffffffffff1p-1022L);
+  TEST (0x0.fffffffffffffp-1022L);
+# endif
+  TEST (0x1p-1022L);
+  TEST (0x1.0000000000001p-1022L);
+  TEST (0x1.00000000001e7p-1022L);
+  TEST (0x1.fffffffffffffp-1022L);
+  TEST (0x1p-1021L);
+  TEST (0x1.00000000000008p-1021L);
+  TEST (0x1.0000000000001p-1021L);
+  TEST (0x1.00000000000018p-1021L);
+  TEST (0x1.0000000000000f8p-1017L);
+  TEST (0x1.0000000000001p-1017L);
+  TEST (0x1.000000000000108p-1017L);
+  TEST (0x1.000000000000dcf8p-1013L);
+  TEST (0x1.000000000000ddp-1013L);
+  TEST (0x1.000000000000dd08p-1013L);
+  TEST (0x1.ffffffffffffffffffffffffffp-1L);
+  TEST (0x1.ffffffffffffffffffffffffff8p-1L);
+  TEST (0x1p+0L);
+  TEST (0x1.000000000000000000000000008p+0L);
+  TEST (0x1.00000000000000000000000001p+0L);
+  TEST (0x1.000000000000000000000000018p+0L);
+  TEST (0x1.23456789abcdef123456789abc8p+0L);
+  TEST (0x1.23456789abcde7123456789abc8p+0L);
+  TEST (0x1.23456789abcdef123456789abc8p+64L);
+  TEST (0x1.23456789abcde7123456789abc8p+64L);
+  TEST (0x1.123456789abcdef123456789p-969L);
+#endif
+  return result;
+}
--- libc/math/test-misc.c.jj	2007-05-24 16:41:05.000000000 +0200
+++ libc/math/test-misc.c	2007-06-01 18:28:29.000000000 +0200
@@ -1235,7 +1235,12 @@ main (void)
     }
 #endif
 
-#if !defined NO_LONG_DOUBLE && LDBL_MANT_DIG >= DBL_MANT_DIG + 4
+/* Skip testing IBM long double format, for 2 reasons:
+   1) it only supports FE_TONEAREST
+   2) nextafter (0.0, 1.0) == nextafterl (0.0L, 1.0L), so
+      nextafter (0.0, 1.0) / 16.0L will be 0.0L.  */
+#if !defined NO_LONG_DOUBLE && LDBL_MANT_DIG >= DBL_MANT_DIG + 4 \
+    && LDBL_MANT_DIG != 106
   int oldmode = fegetround ();
   int j;
   for (j = 0; j < 4; j++)

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]