[1/8] Begin refactor of libm-test.inc

Message ID d07dfc0973a9a1288b424abfb19633ab0048f1c9.1463599718.git.murphyp@linux.vnet.ibm.com
State Superseded
Headers

Commit Message

Paul E. Murphy May 18, 2016, 8:55 p.m. UTC
  Attempt to creatively redefine the macros
to choose tests based on the format being
tested, not the type.

Note, TS 18661 does not define any printf
modifiers, so we need to be a little more
verbose about constructing strings to
output.

	* math/libm-test.inc:
	[MAX_EXP]: Define as (TYPE_MAX_EXP - 1) similar to how
	MANT_DIG and MIN_EXP are defined.
	(ilogb_test_data): Update usage of MAX_EXP.
	(logb_test_data): Likewise.
	[TYPE_DECIMAL_DIG]: Define per C type instead of using CHOOSE().
	[MANT_DIG]: Likewise.
	[MIN_EXP]: Likewise.
	[TYPESTR]: New macro.
	[FSTR_MAX]: Likewise.
	[TEST_COND_binary32]: Likewise.
	[TEST_COND_binary64]: Likewise.
	[TEST_COND_binary128]: Likewise.
	[TEST_COND_ibm128]: Likewise.
	[TEST_COND_intel96]: Likewise.
	[TEST_COND_m68k96]: Likewise.
	[TEST_COND_gt_binary64]: Likewise.
	[M_PI_6l]: Wrap constant with LIT.
	[M_PI_34l]: Likewise.
	[M_PI_34_LOG10El]: Likewise.
	[M_PI2_LOG10El]: Likewise.
	[M_PI4_LOG10El]: Likewise.
	[M_PI_LOG10El]: Likewise.
	[plus_zero]: Replace CHOOSE() with LIT().
	[minus_zero]: Likewise.
	[plus_infty]: Redefine as (TYPE_INF).
	[minus_infty]: Redefine as (-TYPE_INF).
	[max_value]: Redefine as TYPE_MAX.
	[min_value]: Redefine as TYPE_MIN.
	[min_subnorm_value]: Redefined as TYPE_TRUE_MIN.
	(print_float): Make string output compatible with
	strfrom functions defined by TS 18661.
	(update_stats): Likewise.
	(print_complex_function_ulps): Likewise.
	(print_max_error): Likewise.
	(print_complex_max_error): Likewise.
	(check_float_internal): Likewise.
	* math/test-double.h [FTOSTR]: New macro.
	[LIT]: Likewise.
	[TYPE_STR]: Likewise.
	[TYPE_INF]: Likewise.
	[TYPE_DECIMAL_DIG]: Likewise.
	[TYPE_MANT_DIG]: Likewise.
	[TYPE_MAX]: Likewise.
	[TYPE_MIN]: Likewise.
	[TYPE_MIN_EXP]: Likewise.
	[TYPE_TRUE_MIN]: Likewise.
	* math/test-float.h [FTOSTR]: New macro.
	[LIT]: Likewise.
	[TYPE_STR]: Likewise.
	[TYPE_INF]: Likewise.
	[TYPE_DECIMAL_DIG]: Likewise.
	[TYPE_MANT_DIG]: Likewise.
	[TYPE_MAX]: Likewise.
	[TYPE_MIN]: Likewise.
	[TYPE_MIN_EXP]: Likewise.
	[TYPE_TRUE_MIN]: Likewise.
	* math/test-ldouble.h [FTOSTR]: New macro.
	[LIT]: Likewise.
	[TYPE_STR]: Likewise.
	[TYPE_INF]: Likewise.
	[TYPE_DECIMAL_DIG]: Likewise.
	[TYPE_MANT_DIG]: Likewise.
	[TYPE_MAX]: Likewise.
	[TYPE_MIN]: Likewise.
	[TYPE_MIN_EXP]: Likewise.
	[TYPE_TRUE_MIN]: Likewise.
---
 math/libm-test.inc  | 225 ++++++++++++++++++++++++++++------------------------
 math/test-double.h  |  14 ++++
 math/test-float.h   |  14 ++++
 math/test-ldouble.h |  14 ++++
 4 files changed, 163 insertions(+), 104 deletions(-)
  

Comments

Joseph Myers May 18, 2016, 9:16 p.m. UTC | #1
On Wed, 18 May 2016, Paul E. Murphy wrote:

> +#define MANT_DIG (TYPE_MANT_DIG - 1)
> +#define MIN_EXP (TYPE_MIN_EXP - 1)
> +#define MAX_EXP (TYPE_MAX_EXP - 1)

No.  All these "- 1" are gratuitous obfuscation (difference from the 
standard C macros) in the existing code; having similar macros with 
different values is particularly confusing.  The correct approach is a 
preliminary patch to change the definition and uses of MANT_DIG and 
MIN_EXP, rather than extending the use of - 1 to MAX_EXP.

And then you don't need the TYPE_ prefixes at all; just use MAX_EXP etc. 
as at present (I agree that moving away from CHOOSE makes sense).  Only 
TYPE_DECIMAL_DIG (and TYPE_HEX_DIG for consistency) needs such a prefix, 
because of the incompatible meaning of DECIMAL_DIG in <float.h>.

> +#define TYPE_DECIMAL_DIG DBL_DECIMAL_DIG
> +#define TYPE_MIN DBL_MIN
> +#define TYPE_TRUE_MIN DBL_TRUE_MIN
> +#define TYPE_MAX DBL_MAX
> +#define TYPE_MIN_EXP DBL_MIN_EXP
> +#define TYPE_MAX_EXP DBL_MAX_EXP
> +#define TYPE_MANT_DIG DBL_MANT_DIG

Apart from removing the TYPE_ prefix in most cases, I think it would be 
better for this header just to define something to the DBL prefix, and for 
libm-test.inc to deal with concatenating that with _DECIMAL_DIG, _MIN, 
etc.
  
Joseph Myers May 18, 2016, 9:44 p.m. UTC | #2
On Wed, 18 May 2016, Paul E. Murphy wrote:

> 	[TEST_COND_gt_binary64]: Likewise.

I don't like this TEST_COND_gt_binary64.

If the condition combines TEST_LDOUBLE with something about mantissa bits 
or exponents for long double, only the thing about mantissa bits or 
exponents is actually needed.  If it's TEST_LDOUBLE on its own (or 
combined with conditions on integer types rather than on long double), as 
in e.g. tests of ceil, then testing for >= 64 mantissa bits is sufficient 
(the tests may actually only require some number between 53 and 64, but 
testing for >= 64 seems reasonable).  That is, TEST_LDOUBLE on its own can 
be treated as defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64.
  
Paul E. Murphy May 18, 2016, 9:55 p.m. UTC | #3
On 05/18/2016 04:44 PM, Joseph Myers wrote:
> On Wed, 18 May 2016, Paul E. Murphy wrote:
> 
>> 	[TEST_COND_gt_binary64]: Likewise.
> 
> I don't like this TEST_COND_gt_binary64.
> 
> If the condition combines TEST_LDOUBLE with something about mantissa bits 
> or exponents for long double, only the thing about mantissa bits or 
> exponents is actually needed.  If it's TEST_LDOUBLE on its own (or 
> combined with conditions on integer types rather than on long double), as 
> in e.g. tests of ceil, then testing for >= 64 mantissa bits is sufficient 
> (the tests may actually only require some number between 53 and 64, but 
> testing for >= 64 seems reasonable).  That is, TEST_LDOUBLE on its own can 
> be treated as defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64.

Admittedly, I scratched my head here try to find a conservative method to
replace the TEST_LDOUBLE usage.  If it is only used as a bandaid for
testing ldbl formats which are more expressive than dbl, can't it just
go away without issue?  It isn't used in isolation.
  
Joseph Myers May 18, 2016, 10:14 p.m. UTC | #4
On Wed, 18 May 2016, Paul E. Murphy wrote:

> On 05/18/2016 04:44 PM, Joseph Myers wrote:
> > On Wed, 18 May 2016, Paul E. Murphy wrote:
> > 
> >> 	[TEST_COND_gt_binary64]: Likewise.
> > 
> > I don't like this TEST_COND_gt_binary64.
> > 
> > If the condition combines TEST_LDOUBLE with something about mantissa bits 
> > or exponents for long double, only the thing about mantissa bits or 
> > exponents is actually needed.  If it's TEST_LDOUBLE on its own (or 
> > combined with conditions on integer types rather than on long double), as 
> > in e.g. tests of ceil, then testing for >= 64 mantissa bits is sufficient 
> > (the tests may actually only require some number between 53 and 64, but 
> > testing for >= 64 seems reasonable).  That is, TEST_LDOUBLE on its own can 
> > be treated as defined TEST_LDOUBLE && LDBL_MANT_DIG >= 64.
> 
> Admittedly, I scratched my head here try to find a conservative method to
> replace the TEST_LDOUBLE usage.  If it is only used as a bandaid for
> testing ldbl formats which are more expressive than dbl, can't it just
> go away without issue?  It isn't used in isolation.

The aim is to replace it with a logical condition for what the tests in 
question require.

If the condition just is "#ifdef TEST_LDOUBLE" (possibly with extra 
whitespace after "#"), or just tests defined TEST_LDOUBLE without any 
MANT_DIG, MIN_EXP or MAX_EXP tests (but including e.g. the "# if LONG_MAX 
> 281474976710656 && defined TEST_LDOUBLE" condition on one test of 
lrint), then, in what follows, treat it like "defined TEST_LDOUBLE && 
LDBL_MANT_DIG >= 64".

Given a test of a combination of TEST_LDOUBLE with a test of 
LDBL_MANT_DIG, LDBL_MIN_EXP or LDBL_MAX_EXP (possibly more than one of 
those, and possibly with other tests such as LONG_MAX as well), you can 
then remove the TEST_LDOUBLE condition if you change the LDBL_* tests to 
test the macros such as MANT_DIG, MIN_EXP and MAX_EXP (with MANT_DIG and 
MIN_EXP having previously been adjusted to remove the "-1").

Perhaps this patch is doing too many things and you need some patches just 
about refactoring TEST_LDOUBLE uses.

* Adjust MANT_DIG and MIN_EXP not to use -1.

* Change TEST_LDOUBLE when it appears in conjunction with LDBL_MANT_DIG 
etc. tests to just test MANT_DIG etc.

* Change LDBL_MANT_DIG etc. conditionals inside of TEST_LDOUBLE ones 
similarly (for cases such as

#ifdef TEST_LDOUBLE
...
# if LDBL_MANT_DIG > 100
...
# endif
#endif

* Change TEST_LDOUBLE when it appears on its own to test MANT_DIG >= 64.

(Well, all but the first of those could reasonbly go together in one 
patch, if separated from the rest of the refactoring.)
  

Patch

diff --git a/math/libm-test.inc b/math/libm-test.inc
index f1ba7dd..5fabf4d 100644
--- a/math/libm-test.inc
+++ b/math/libm-test.inc
@@ -184,31 +184,77 @@  struct ulp_data
 #define IGNORE_RESULT			0x20000
 #define NON_FINITE			0x40000
 
+#define MANT_DIG (TYPE_MANT_DIG - 1)
+#define MIN_EXP (TYPE_MIN_EXP - 1)
+#define MAX_EXP (TYPE_MAX_EXP - 1)
+
+/* Maximum character buffer to store a stringitized FLOAT value. */
+# define FSTR_MAX (128)
+
+#if TEST_INLINE
+# define TYPESTR "i" TYPE_STR
+#else
+# define TYPESTR TYPE_STR
+#endif
+
+/* Format specific test macros.  */
+#define TEST_COND_binary32 (TYPE_MANT_DIG == 24		\
+			    && TYPE_MIN_EXP == -125	\
+			    && TYPE_MAX_EXP == 128)
+
+#define TEST_COND_binary64 (TYPE_MANT_DIG == 53		\
+			    && TYPE_MIN_EXP == -1021	\
+			    && TYPE_MAX_EXP == 1024)
+
+#define TEST_COND_binary128 (TYPE_MANT_DIG == 113	\
+			     && TYPE_MIN_EXP == -16381	\
+			     && TYPE_MAX_EXP == 16384)
+
+#define TEST_COND_ibm128 (TYPE_MANT_DIG == 106)
+
+#define TEST_COND_intel96 (TYPE_MANT_DIG == 64		\
+			   && TYPE_MIN_EXP == -16381	\
+			   && TYPE_MAX_EXP == 16384)
+
+#define TEST_COND_m68k96 (TYPE_MANT_DIG == 64		\
+			  && TYPE_MIN_EXP == -16382	\
+			  && TYPE_MAX_EXP == 16384)
+
+/* This is a standin replacement for the usage of TEST_LDOUBLE
+   to enable certain tests for the format/type.  Instead, we
+   enable them if some trait of the format is more expressive
+   than the binary64 format.  */
+#define TEST_COND_gt_binary64 (TYPE_MANT_DIG > 53	\
+			       || TYPE_MIN_EXP < -1021	\
+			       || TYPE_MAX_EXP > 1024  )
+
 /* Values underflowing only for float.  */
-#ifdef TEST_FLOAT
+#if TEST_COND_binary32
 # define UNDERFLOW_EXCEPTION_FLOAT	UNDERFLOW_EXCEPTION
 # define UNDERFLOW_EXCEPTION_OK_FLOAT	UNDERFLOW_EXCEPTION_OK
 #else
 # define UNDERFLOW_EXCEPTION_FLOAT	0
 # define UNDERFLOW_EXCEPTION_OK_FLOAT	0
 #endif
+
 /* Values underflowing only for double or types with a larger least
    positive normal value.  */
-#if defined TEST_FLOAT || defined TEST_DOUBLE \
-  || (defined TEST_LDOUBLE && LDBL_MIN_EXP >= DBL_MIN_EXP)
+#if TEST_COND_binary32 || TEST_COND_binary64 || TEST_COND_ibm128
 # define UNDERFLOW_EXCEPTION_DOUBLE	UNDERFLOW_EXCEPTION
 # define UNDERFLOW_EXCEPTION_OK_DOUBLE	UNDERFLOW_EXCEPTION_OK
 #else
 # define UNDERFLOW_EXCEPTION_DOUBLE	0
 # define UNDERFLOW_EXCEPTION_OK_DOUBLE	0
 #endif
+
 /* Values underflowing only for IBM long double or types with a larger least
    positive normal value.  */
-#if defined TEST_FLOAT || (defined TEST_LDOUBLE && LDBL_MIN_EXP > DBL_MIN_EXP)
+#if TEST_COND_binary32 || TEST_COND_ibm128
 # define UNDERFLOW_EXCEPTION_LDOUBLE_IBM	UNDERFLOW_EXCEPTION
 #else
 # define UNDERFLOW_EXCEPTION_LDOUBLE_IBM	0
 #endif
+
 /* Values underflowing on architectures detecting tininess before
    rounding, but not on those detecting tininess after rounding.  */
 #define UNDERFLOW_EXCEPTION_BEFORE_ROUNDING	(TININESS_AFTER_ROUNDING \
@@ -228,36 +274,13 @@  struct ulp_data
 #endif
 
 /* Conditions used by tests generated by gen-auto-libm-tests.c.  */
-#ifdef TEST_FLOAT
-# define TEST_COND_flt_32	1
-#else
-# define TEST_COND_flt_32	0
-#endif
-#if defined TEST_DOUBLE || (defined TEST_LDOUBLE && LDBL_MANT_DIG == 53)
-# define TEST_COND_dbl_64	1
-#else
-# define TEST_COND_dbl_64	0
-#endif
-#if defined TEST_LDOUBLE && LDBL_MANT_DIG == 64 && LDBL_MIN_EXP == -16381
-# define TEST_COND_ldbl_96_intel	1
-#else
-# define TEST_COND_ldbl_96_intel	0
-#endif
-#if defined TEST_LDOUBLE && LDBL_MANT_DIG == 64 && LDBL_MIN_EXP == -16382
-# define TEST_COND_ldbl_96_m68k	1
-#else
-# define TEST_COND_ldbl_96_m68k	0
-#endif
-#if defined TEST_LDOUBLE && LDBL_MANT_DIG == 113
-# define TEST_COND_ldbl_128	1
-#else
-# define TEST_COND_ldbl_128	0
-#endif
-#if defined TEST_LDOUBLE && LDBL_MANT_DIG == 106
-# define TEST_COND_ldbl_128ibm	1
-#else
-# define TEST_COND_ldbl_128ibm	0
-#endif
+#define TEST_COND_flt_32 TEST_COND_binary32
+#define TEST_COND_dbl_64 TEST_COND_binary64
+#define TEST_COND_ldbl_96_intel TEST_COND_intel96
+#define TEST_COND_ldbl_96_m68k  TEST_COND_m68k96
+#define TEST_COND_ldbl_128 TEST_COND_binary128
+#define TEST_COND_ldbl_128ibm TEST_COND_ibm128
+
 #if LONG_MAX == 0x7fffffff
 # define TEST_COND_long32	1
 # define TEST_COND_long64	0
@@ -281,12 +304,12 @@  struct ulp_data
 #endif
 
 /* Various constants (we must supply them precalculated for accuracy).  */
-#define M_PI_6l			.52359877559829887307710723054658383L
-#define M_PI_34l		2.356194490192344928846982537459627163L	/* 3*pi/4 */
-#define M_PI_34_LOG10El		1.023282265381381010614337719073516828L
-#define M_PI2_LOG10El		0.682188176920920673742891812715677885L
-#define M_PI4_LOG10El		0.341094088460460336871445906357838943L
-#define M_PI_LOG10El		1.364376353841841347485783625431355770L
+#define M_PI_6l			LIT (.52359877559829887307710723054658383)
+#define M_PI_34l		LIT (2.356194490192344928846982537459627163) /* 3*pi/4 */
+#define M_PI_34_LOG10El		LIT (1.023282265381381010614337719073516828)
+#define M_PI2_LOG10El		LIT (0.682188176920920673742891812715677885)
+#define M_PI4_LOG10El		LIT (0.341094088460460336871445906357838943)
+#define M_PI_LOG10El		LIT (1.364376353841841347485783625431355770)
 
 #define ulps_file_name "ULPs"	/* Name of the ULPs file.  */
 static FILE *ulps_file;		/* File to document difference.  */
@@ -303,25 +326,14 @@  static int output_max_error;	/* Should the maximal errors printed?  */
 static int output_points;	/* Should the single function results printed?  */
 static int ignore_max_ulp;	/* Should we ignore max_ulp?  */
 
-#define plus_zero	CHOOSE (0.0L, 0.0, 0.0f,	\
-				0.0L, 0.0, 0.0f)
-#define minus_zero	CHOOSE (-0.0L, -0.0, -0.0f,	\
-				-0.0L, -0.0, -0.0f)
-#define plus_infty	CHOOSE (HUGE_VALL, HUGE_VAL, HUGE_VALF, \
-				HUGE_VALL, HUGE_VAL, HUGE_VALF)
-#define minus_infty	CHOOSE (-HUGE_VALL, -HUGE_VAL, -HUGE_VALF,	\
-				-HUGE_VALL, -HUGE_VAL, -HUGE_VALF)
+#define plus_zero	LIT (0.0)
+#define minus_zero	LIT (-0.0)
+#define plus_infty	(TYPE_INF)
+#define minus_infty	(-TYPE_INF)
 #define qnan_value	FUNC (__builtin_nan) ("")
-#define max_value	CHOOSE (LDBL_MAX, DBL_MAX, FLT_MAX,	\
-				LDBL_MAX, DBL_MAX, FLT_MAX)
-#define min_value	CHOOSE (LDBL_MIN, DBL_MIN, FLT_MIN,	\
-				LDBL_MIN, DBL_MIN, FLT_MIN)
-#define min_subnorm_value	CHOOSE (LDBL_TRUE_MIN,	\
-					DBL_TRUE_MIN,	\
-					FLT_TRUE_MIN,	\
-					LDBL_TRUE_MIN,	\
-					DBL_TRUE_MIN,	\
-					FLT_TRUE_MIN)
+#define max_value	TYPE_MAX
+#define min_value	TYPE_MIN
+#define min_subnorm_value TYPE_TRUE_MIN
 
 static FLOAT max_error, real_max_error, imag_max_error;
 
@@ -329,23 +341,11 @@  static FLOAT prev_max_error, prev_real_max_error, prev_imag_max_error;
 
 static FLOAT max_valid_error;
 
-#define MANT_DIG CHOOSE ((LDBL_MANT_DIG-1), (DBL_MANT_DIG-1), (FLT_MANT_DIG-1),  \
-			 (LDBL_MANT_DIG-1), (DBL_MANT_DIG-1), (FLT_MANT_DIG-1))
-#define MIN_EXP CHOOSE ((LDBL_MIN_EXP-1), (DBL_MIN_EXP-1), (FLT_MIN_EXP-1),	\
-			(LDBL_MIN_EXP-1), (DBL_MIN_EXP-1), (FLT_MIN_EXP-1))
-#define MAX_EXP CHOOSE (LDBL_MAX_EXP, DBL_MAX_EXP, FLT_MAX_EXP, \
-			LDBL_MAX_EXP, DBL_MAX_EXP, FLT_MAX_EXP)
 /* Sufficient numbers of digits to represent any floating-point value
    unambiguously (for any choice of the number of bits in the first
    hex digit, in the case of TYPE_HEX_DIG).  When used with printf
    formats where the precision counts only digits after the point, 1
    is subtracted from these values. */
-#define TYPE_DECIMAL_DIG CHOOSE (LDBL_DECIMAL_DIG,	\
-				 DBL_DECIMAL_DIG,	\
-				 FLT_DECIMAL_DIG,	\
-				 LDBL_DECIMAL_DIG,	\
-				 DBL_DECIMAL_DIG,	\
-				 FLT_DECIMAL_DIG)
 #define TYPE_HEX_DIG ((MANT_DIG + 7) / 4)
 
 /* Compare KEY (a string, with the name of a function) with ULP (a
@@ -428,8 +428,12 @@  print_float (FLOAT f)
   else if (isnan (f))
     printf ("qNaN\n");
   else
-    printf ("% .*" PRINTF_EXPR "  % .*" PRINTF_XEXPR "\n",
-	    TYPE_DECIMAL_DIG - 1, f, TYPE_HEX_DIG - 1, f);
+    {
+      char fstrn[FSTR_MAX], fstrx[FSTR_MAX];
+      FTOSTR (fstrn, FSTR_MAX, "% .*" PRINTF_EXPR, TYPE_DECIMAL_DIG - 1, f);
+      FTOSTR (fstrx, FSTR_MAX, "% .*" PRINTF_XEXPR, TYPE_HEX_DIG - 1, f);
+      printf ("%s  %s\n", fstrn, fstrx);
+    }
 }
 
 /* Should the message print to screen?  This depends on the verbose flag,
@@ -471,11 +475,10 @@  print_function_ulps (const char *function_name, FLOAT ulp)
 {
   if (output_ulps)
     {
+      char ustrn[FSTR_MAX];
+      FTOSTR (ustrn, FSTR_MAX, "%.0" PRINTF_NEXPR, FUNC (ceil) (ulp));
       fprintf (ulps_file, "Function: \"%s\":\n", function_name);
-      fprintf (ulps_file, "%s: %.0" PRINTF_NEXPR "\n",
-	       CHOOSE("ldouble", "double", "float",
-		      "ildouble", "idouble", "ifloat"),
-	       FUNC(ceil) (ulp));
+      fprintf (ulps_file, TYPESTR ": %s\n", ustrn);
     }
 }
 
@@ -486,21 +489,20 @@  print_complex_function_ulps (const char *function_name, FLOAT real_ulp,
 {
   if (output_ulps)
     {
+      char fstrn[FSTR_MAX];
       if (real_ulp != 0.0)
 	{
+	  FTOSTR (fstrn, FSTR_MAX, "%.0" PRINTF_NEXPR,
+	            FUNC (ceil) (real_ulp));
 	  fprintf (ulps_file, "Function: Real part of \"%s\":\n", function_name);
-	  fprintf (ulps_file, "%s: %.0" PRINTF_NEXPR "\n",
-		   CHOOSE("ldouble", "double", "float",
-			  "ildouble", "idouble", "ifloat"),
-		   FUNC(ceil) (real_ulp));
+	  fprintf (ulps_file, TYPESTR ": %s\n", fstrn);
 	}
       if (imag_ulp != 0.0)
 	{
+	  FTOSTR (fstrn, FSTR_MAX, "%.0" PRINTF_NEXPR,
+	            FUNC (ceil) (imag_ulp));
 	  fprintf (ulps_file, "Function: Imaginary part of \"%s\":\n", function_name);
-	  fprintf (ulps_file, "%s: %.0" PRINTF_NEXPR "\n",
-		   CHOOSE("ldouble", "double", "float",
-			  "ildouble", "idouble", "ifloat"),
-		   FUNC(ceil) (imag_ulp));
+	  fprintf (ulps_file, TYPESTR ": %s\n", fstrn);
 	}
 
 
@@ -548,10 +550,12 @@  print_max_error (const char *func_name)
 
   if (print_screen_max_error (ok))
     {
+      char mestr[FSTR_MAX], pmestr[FSTR_MAX];
+      FTOSTR (mestr, FSTR_MAX, "%.0" PRINTF_NEXPR, FUNC (ceil) (max_error));
+      FTOSTR (pmestr, FSTR_MAX, "%.0" PRINTF_NEXPR, FUNC (ceil) (prev_max_error));
       printf ("Maximal error of `%s'\n", func_name);
-      printf (" is      : %.0" PRINTF_NEXPR " ulp\n", FUNC(ceil) (max_error));
-      printf (" accepted: %.0" PRINTF_NEXPR " ulp\n",
-	      FUNC(ceil) (prev_max_error));
+      printf (" is      : %s ulp\n", mestr);
+      printf (" accepted: %s ulp\n", pmestr);
     }
 
   update_stats (ok);
@@ -584,16 +588,22 @@  print_complex_max_error (const char *func_name)
 
   if (print_screen_max_error (ok))
     {
+      char rmestr[FSTR_MAX], prmestr[FSTR_MAX];
+      char imestr[FSTR_MAX], pimestr[FSTR_MAX];
+      FTOSTR (rmestr, FSTR_MAX, "%.0" PRINTF_NEXPR,
+		FUNC (ceil) (real_max_error));
+      FTOSTR (prmestr, FSTR_MAX, "%.0" PRINTF_NEXPR,
+		FUNC (ceil) (prev_real_max_error));
+      FTOSTR (imestr, FSTR_MAX, "%.0" PRINTF_NEXPR,
+		FUNC (ceil) (imag_max_error));
+      FTOSTR (pimestr, FSTR_MAX, "%.0" PRINTF_NEXPR,
+		FUNC (ceil) (prev_imag_max_error));
       printf ("Maximal error of real part of: %s\n", func_name);
-      printf (" is      : %.0" PRINTF_NEXPR " ulp\n",
-	      FUNC(ceil) (real_max_error));
-      printf (" accepted: %.0" PRINTF_NEXPR " ulp\n",
-	      FUNC(ceil) (prev_real_max_error));
+      printf (" is      : %s ulp\n", rmestr);
+      printf (" accepted: %s ulp\n", prmestr);
       printf ("Maximal error of imaginary part of: %s\n", func_name);
-      printf (" is      : %.0" PRINTF_NEXPR " ulp\n",
-	      FUNC(ceil) (imag_max_error));
-      printf (" accepted: %.0" PRINTF_NEXPR " ulp\n",
-	      FUNC(ceil) (prev_imag_max_error));
+      printf (" is      : %s ulp\n", imestr);
+      printf (" accepted: %s ulp\n", pimestr);
     }
 
   update_stats (ok);
@@ -749,7 +759,7 @@  ulp (FLOAT value)
 	   2^(-MANT_DIG) which is too large a value to be useful. Note that we
 	   can't use ilogb(0), since that isn't a valid thing to do. As a point
 	   of comparison Java's ulp returns the next normal value e.g.
-	   2^(1 - MAX_EXP) for ulp(0), but that is not what we want for
+	   2^(1 - TYPE_MAX_EXP) for ulp(0), but that is not what we want for
 	   glibc.  */
 	/* Fall through...  */
       case FP_SUBNORMAL:
@@ -851,10 +861,17 @@  check_float_internal (const char *test_name, FLOAT computed, FLOAT expected,
       print_float (expected);
       if (print_diff)
 	{
-	  printf (" difference: % .*" PRINTF_EXPR "  % .*" PRINTF_XEXPR
-		  "\n", TYPE_DECIMAL_DIG - 1, diff, TYPE_HEX_DIG - 1, diff);
-	  printf (" ulp       : % .4" PRINTF_NEXPR "\n", ulps);
-	  printf (" max.ulp   : % .4" PRINTF_NEXPR "\n", max_ulp);
+	  char dstrn[FSTR_MAX], dstrx[FSTR_MAX];
+	  char ustrn[FSTR_MAX], mustrn[FSTR_MAX];
+	  FTOSTR (dstrn, FSTR_MAX, "% .*" PRINTF_EXPR,
+		  TYPE_DECIMAL_DIG - 1, diff);
+	  FTOSTR (dstrx, FSTR_MAX, "% .*" PRINTF_XEXPR,
+		  TYPE_HEX_DIG - 1, diff);
+	  FTOSTR (ustrn, FSTR_MAX, "% .4" PRINTF_NEXPR, ulps);
+	  FTOSTR (mustrn, FSTR_MAX, "% .4" PRINTF_NEXPR, max_ulp);
+	  printf (" difference: %s  %s\n", dstrn, dstrx);
+	  printf (" ulp       : %s\n", ustrn);
+	  printf (" max.ulp   : %s\n", mustrn);
 	}
     }
   update_stats (ok);
@@ -7897,8 +7914,8 @@  static const struct test_f_i_data ilogb_test_data[] =
     TEST_f_i (ilogb, -min_subnorm_value, MIN_EXP-MANT_DIG, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
     TEST_f_i (ilogb, min_value, MIN_EXP, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
     TEST_f_i (ilogb, -min_value, MIN_EXP, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
-    TEST_f_i (ilogb, max_value, MAX_EXP-1, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
-    TEST_f_i (ilogb, -max_value, MAX_EXP-1, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
+    TEST_f_i (ilogb, max_value, MAX_EXP, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
+    TEST_f_i (ilogb, -max_value, MAX_EXP, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
 
     /* ilogb (0.0) == FP_ILOGB0 plus invalid exception  */
     TEST_f_i (ilogb, 0.0, FP_ILOGB0, NO_INEXACT_EXCEPTION|INVALID_EXCEPTION|ERRNO_EDOM),
@@ -9030,8 +9047,8 @@  static const struct test_f_f_data logb_test_data[] =
     TEST_f_f (logb, -min_subnorm_value, MIN_EXP-MANT_DIG, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
     TEST_f_f (logb, min_value, MIN_EXP, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
     TEST_f_f (logb, -min_value, MIN_EXP, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
-    TEST_f_f (logb, max_value, MAX_EXP-1, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
-    TEST_f_f (logb, -max_value, MAX_EXP-1, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
+    TEST_f_f (logb, max_value, MAX_EXP, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
+    TEST_f_f (logb, -max_value, MAX_EXP, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED);
 
     TEST_f_f (logb, 0x0.1p-127, -131, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
     TEST_f_f (logb, 0x0.01p-127, -135, NO_INEXACT_EXCEPTION|ERRNO_UNCHANGED),
diff --git a/math/test-double.h b/math/test-double.h
index 16b4ce8..2fabf57 100644
--- a/math/test-double.h
+++ b/math/test-double.h
@@ -16,6 +16,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <float.h>
+
 #define FUNC(function) function
 #define FLOAT double
 #define PRINTF_EXPR "e"
@@ -23,3 +25,15 @@ 
 #define PRINTF_NEXPR "f"
 #define TEST_DOUBLE 1
 #define BUILD_COMPLEX(real, imag) (CMPLX ((real), (imag)))
+
+#define LIT(x) (x)
+#define FTOSTR snprintf
+#define TYPE_STR "double"
+#define TYPE_DECIMAL_DIG DBL_DECIMAL_DIG
+#define TYPE_MIN DBL_MIN
+#define TYPE_TRUE_MIN DBL_TRUE_MIN
+#define TYPE_MAX DBL_MAX
+#define TYPE_MIN_EXP DBL_MIN_EXP
+#define TYPE_MAX_EXP DBL_MAX_EXP
+#define TYPE_MANT_DIG DBL_MANT_DIG
+#define TYPE_INF HUGE_VAL
diff --git a/math/test-float.h b/math/test-float.h
index 629f6ee..a54e815 100644
--- a/math/test-float.h
+++ b/math/test-float.h
@@ -16,6 +16,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <float.h>
+
 #define FUNC(function) function ## f
 #define FLOAT float
 #define PRINTF_EXPR "e"
@@ -23,3 +25,15 @@ 
 #define PRINTF_NEXPR "f"
 #define TEST_FLOAT 1
 #define BUILD_COMPLEX(real, imag) (CMPLXF ((real), (imag)))
+
+#define LIT(x) (x ## f)
+#define FTOSTR snprintf
+#define TYPE_STR "float"
+#define TYPE_INF HUGE_VALF
+#define TYPE_DECIMAL_DIG FLT_DECIMAL_DIG
+#define TYPE_MANT_DIG FLT_MANT_DIG
+#define TYPE_MAX FLT_MAX
+#define TYPE_MAX_EXP FLT_MAX_EXP
+#define TYPE_MIN FLT_MIN
+#define TYPE_MIN_EXP FLT_MIN_EXP
+#define TYPE_TRUE_MIN FLT_TRUE_MIN
diff --git a/math/test-ldouble.h b/math/test-ldouble.h
index 481561f..dee158a 100644
--- a/math/test-ldouble.h
+++ b/math/test-ldouble.h
@@ -16,6 +16,8 @@ 
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <float.h>
+
 #define FUNC(function) function##l
 #define FLOAT long double
 #define PRINTF_EXPR "Le"
@@ -23,3 +25,15 @@ 
 #define PRINTF_NEXPR "Lf"
 #define TEST_LDOUBLE 1
 #define BUILD_COMPLEX(real, imag) (CMPLXL ((real), (imag)))
+
+#define LIT(x) (x ## L)
+#define FTOSTR snprintf
+#define TYPE_STR "ldouble"
+#define TYPE_DECIMAL_DIG LDBL_DECIMAL_DIG
+#define TYPE_MIN LDBL_MIN
+#define TYPE_TRUE_MIN LDBL_TRUE_MIN
+#define TYPE_MAX LDBL_MAX
+#define TYPE_MIN_EXP LDBL_MIN_EXP
+#define TYPE_MAX_EXP LDBL_MAX_EXP
+#define TYPE_MANT_DIG LDBL_MANT_DIG
+#define TYPE_INF HUGE_VALL