Blame stdlib/tst-strtod-round-skeleton.c

Packit 6c4009
/* Test for correct rounding of results of strtod and related
Packit 6c4009
   functions.
Packit 6c4009
   Copyright (C) 2012-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* Defining _LIBC_TEST ensures long double math functions are
Packit 6c4009
   declared in the headers.  */
Packit 6c4009
#define _LIBC_TEST 1
Packit 6c4009
#define __STDC_WANT_IEC_60559_TYPES_EXT__
Packit 6c4009
#include <fenv.h>
Packit 6c4009
#include <float.h>
Packit 6c4009
#include <math.h>
Packit 6c4009
#include <stdbool.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <math-tests.h>
Packit 6c4009
Packit 6c4009
#include "tst-strtod.h"
Packit 6c4009
Packit 6c4009
/* Non-standard macros expected to be externally defined:
Packit 6c4009
Packit 6c4009
   L_(str): Pastes the appropriate modifier to a string literal str.
Packit 6c4009
Packit 6c4009
   FNPFX: Expands to the correct prefix for the strtod equivalent
Packit 6c4009
          of type CHAR. (e.g str or wcs).
Packit 6c4009
Packit 6c4009
   CHAR: Expands to the string type being tested (e.g wchar_t or char).
Packit 6c4009
Packit 6c4009
   STRM: Expands to a string literal suitable for printing CHAR* via
Packit 6c4009
         printf (e.g "%s" or "%ls"). */
Packit 6c4009
Packit 6c4009
#define _CONCAT(a, b) a ## b
Packit 6c4009
#define CONCAT(a, b) _CONCAT (a, b)
Packit 6c4009
Packit 6c4009
#define STRTO(x) CONCAT (CONCAT (FNPFX, to), x)
Packit 6c4009
Packit 6c4009
#if LDBL_MANT_DIG == 106 && LDBL_MAX_EXP == 1024
Packit 6c4009
/* This is a stupid hack for IBM long double.  This test ignores
Packit 6c4009
   inexact values for long double due to the limitations of the
Packit 6c4009
   format.  This ensures rounding tests are ignored.  */
Packit 6c4009
# undef ROUNDING_TESTS_long_double
Packit 6c4009
# define ROUNDING_TESTS_long_double(x) 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Generator to create an FTYPE member variabled named FSUF
Packit 6c4009
   used to populate struct member variables.  */
Packit 6c4009
#define FTYPE_MEMBER(FSUF, FTYPE, FTOSTR, LSUF, CSUF)  \
Packit 6c4009
       FTYPE FSUF;
Packit 6c4009
Packit 6c4009
/* Likewise, but each member is of type bool.  */
Packit 6c4009
#define BOOL_MEMBER(FSUF, FTYPE, FTOSTR, LSUF, CSUF)  \
Packit 6c4009
       bool FSUF;
Packit 6c4009
Packit 6c4009
#define STRUCT_FOREACH_FLOAT_FTYPE GEN_TEST_STRTOD_FOREACH (FTYPE_MEMBER)
Packit 6c4009
#define STRUCT_FOREACH_FLOAT_BOOL GEN_TEST_STRTOD_FOREACH (BOOL_MEMBER)
Packit 6c4009
Packit 6c4009
/* Define the long double choose (CHOOSE_ld) macro
Packit 6c4009
   to select the appropriate generated long double
Packit 6c4009
   value from the generated test data.  */
Packit 6c4009
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
Packit 6c4009
/* This is for the long double == double format.  */
Packit 6c4009
# define CHOOSE_ld(f,d,...) d
Packit 6c4009
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16381
Packit 6c4009
/* This is for the Intel extended float format.  */
Packit 6c4009
# define CHOOSE_ld(f,d,ld64i,...) ld64i
Packit 6c4009
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16382
Packit 6c4009
/* This is for the Motorola extended float format.  */
Packit 6c4009
# define CHOOSE_ld(f,d,ld64i,ld64m,...) ld64m
Packit 6c4009
#elif LDBL_MANT_DIG == 106 && LDBL_MAX_EXP == 1024
Packit 6c4009
/* This is for the IBM extended double format.  */
Packit 6c4009
# define CHOOSE_ld(f,d,ld64i,ld64m,ld106,...) ld106
Packit 6c4009
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
Packit 6c4009
/* This is for the IEEE binary128 format.  */
Packit 6c4009
# define CHOOSE_ld(f,d,ld64i,ld64m,ld106,ld113,...) ld113
Packit 6c4009
#else
Packit 6c4009
# error "unknown long double format"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Add type specific choosing macros below.  */
Packit 6c4009
#define CHOOSE_f(f,...) f
Packit 6c4009
#define CHOOSE_f32(f,...) f
Packit 6c4009
#define CHOOSE_d(f,d,...) d
Packit 6c4009
#define CHOOSE_f64(f,d,...) d
Packit 6c4009
#define CHOOSE_f32x(f,d,...) d
Packit 6c4009
#define CHOOSE_f128(f,d,ld64i,ld64m,ld106,ld113,...) ld113
Packit 6c4009
/* long double is special, and handled above.  _Float16 would require
Packit 6c4009
   updates to the generator to generate appropriate expectations, and
Packit 6c4009
   updates to the test inputs to cover difficult rounding cases for
Packit 6c4009
   _Float16.  */
Packit 6c4009
Packit 6c4009
#if __HAVE_FLOAT64X
Packit 6c4009
# if FLT64X_MANT_DIG == 113 && FLT64X_MAX_EXP == 16384
Packit 6c4009
#  define CHOOSE_f64x(f,d,ld64i,ld64m,ld106,ld113,...) ld113
Packit 6c4009
# elif (FLT64X_MANT_DIG == 64			\
Packit 6c4009
	&& FLT64X_MAX_EXP == 16384		\
Packit 6c4009
	&& FLT64X_MIN_EXP == -16381)
Packit 6c4009
#  define CHOOSE_f64x(f,d,ld64i,...) ld64i
Packit 6c4009
# else
Packit 6c4009
#  error "unknown _Float64x format"
Packit 6c4009
# endif
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Selector for expected result field of a given type.  */
Packit 6c4009
#define _ENTRY(FSUF, FTYPE, FTOSTR, LSUF, CSUF, ...)  \
Packit 6c4009
  CONCAT (CHOOSE_ ## FSUF (__VA_ARGS__), LSUF),
Packit 6c4009
#define ENTRY(...) \
Packit 6c4009
  GEN_TEST_STRTOD_FOREACH (_ENTRY, __VA_ARGS__)
Packit 6c4009
Packit 6c4009
/* Selector for boolean exact tag of expected results and that for
Packit 6c4009
   overflow.  */
Packit 6c4009
#define _XNTRY(FSUF, FTYPE, FTOSTR, LSUF, CSUF, ...)  \
Packit 6c4009
  CHOOSE_ ## FSUF (__VA_ARGS__),
Packit 6c4009
#define XNTRY(...) \
Packit 6c4009
  GEN_TEST_STRTOD_FOREACH (_XNTRY, __VA_ARGS__)
Packit 6c4009
Packit 6c4009
/* This is hacky way around the seemingly unavoidable macro
Packit 6c4009
   expansion of the INFINITY or HUGE_VAL like macros in the
Packit 6c4009
   above.  It is assumed the compiler will implicitly convert
Packit 6c4009
   the infinity correctly.  */
Packit 6c4009
#define INF INFINITY + 0.0
Packit 6c4009
Packit 6c4009
/* This macro is used in conjunction with the output from the
Packit 6c4009
   gen-tst-strtod-round utility to select the appropriately
Packit 6c4009
   rounded long double value for a given format.  */
Packit 6c4009
#define TEST(s,							\
Packit 6c4009
	     fx, fd, fdo, fn, fno, fz, fzo, fu, fuo,		\
Packit 6c4009
	     dx, dd, ddo, dn, dno, dz, dzo, du, duo,		\
Packit 6c4009
	     ld64ix, ld64id, ld64ido, ld64in, ld64ino,		\
Packit 6c4009
	     ld64iz, ld64izo, ld64iu, ld64iuo,			\
Packit 6c4009
	     ld64mx, ld64md, ld64mdo, ld64mn, ld64mno,		\
Packit 6c4009
	     ld64mz, ld64mzo, ld64mu, ld64muo,			\
Packit 6c4009
	     ld106x, ld106d, ld106do, ld106n, ld106no,		\
Packit 6c4009
	     ld106z, ld106zo, ld106u, ld106uo,			\
Packit 6c4009
	     ld113x, ld113d, ld113do, ld113n, ld113no,		\
Packit 6c4009
	     ld113z, ld113zo, ld113u, ld113uo)			\
Packit 6c4009
  {								\
Packit 6c4009
    L_ (s),							\
Packit 6c4009
    { XNTRY (fx, dx, ld64ix, ld64mx, ld106x, ld113x) },		\
Packit 6c4009
    {								\
Packit 6c4009
    { ENTRY (fn, dn, ld64in, ld64mn, ld106n, ld113n) },		\
Packit 6c4009
    { ENTRY (fd, dd, ld64id, ld64md, ld106d, ld113d) },		\
Packit 6c4009
    { ENTRY (fz, dz, ld64iz, ld64mz, ld106z, ld113z) },		\
Packit 6c4009
    { ENTRY (fu, du, ld64iu, ld64mu, ld106u, ld113u) }		\
Packit 6c4009
    },								\
Packit 6c4009
    {								\
Packit 6c4009
    { XNTRY (fno, dno, ld64ino, ld64mno, ld106no, ld113no) },	\
Packit 6c4009
    { XNTRY (fdo, ddo, ld64ido, ld64mdo, ld106do, ld113do) },	\
Packit 6c4009
    { XNTRY (fzo, dzo, ld64izo, ld64mzo, ld106zo, ld113zo) },	\
Packit 6c4009
    { XNTRY (fuo, duo, ld64iuo, ld64muo, ld106uo, ld113uo) }	\
Packit 6c4009
    }								\
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
struct test_exactness
Packit 6c4009
  {
Packit 6c4009
  STRUCT_FOREACH_FLOAT_BOOL
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
struct test_results
Packit 6c4009
  {
Packit 6c4009
  STRUCT_FOREACH_FLOAT_FTYPE
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
struct test_overflow
Packit 6c4009
  {
Packit 6c4009
  STRUCT_FOREACH_FLOAT_BOOL
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
struct test {
Packit 6c4009
  const CHAR *s;
Packit 6c4009
  struct test_exactness exact;
Packit 6c4009
  struct test_results r[4];
Packit 6c4009
  struct test_overflow o[4];
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
/* Include the generated test data.  */
Packit 6c4009
#include "tst-strtod-round-data.h"
Packit 6c4009
Packit 6c4009
#define STRX(x) #x
Packit 6c4009
#define STR(x) STRX (x)
Packit 6c4009
#define FNPFXS STR (FNPFX)
Packit 6c4009
Packit 6c4009
#ifndef FE_INEXACT
Packit 6c4009
# define FE_INEXACT 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef FE_OVERFLOW
Packit 6c4009
# define FE_OVERFLOW 0
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#define GEN_ONE_TEST(FSUF, FTYPE, FTOSTR, LSUF, CSUF)		\
Packit 6c4009
{								\
Packit 6c4009
  feclearexcept (FE_ALL_EXCEPT);				\
Packit 6c4009
  FTYPE f = STRTO (FSUF) (s, NULL);				\
Packit 6c4009
  if (f != expected->FSUF					\
Packit 6c4009
      || (copysign ## CSUF) (1.0 ## LSUF, f)			\
Packit 6c4009
	 != (copysign ## CSUF) (1.0 ## LSUF, expected->FSUF))	\
Packit 6c4009
    {								\
Packit 6c4009
      char efstr[FSTRLENMAX];					\
Packit 6c4009
      char fstr[FSTRLENMAX];					\
Packit 6c4009
      FTOSTR (efstr, FSTRLENMAX, "%a", expected->FSUF);		\
Packit 6c4009
      FTOSTR (fstr, FSTRLENMAX, "%a", f);			\
Packit 6c4009
      printf (FNPFXS "to" #FSUF  " (" STRM ") returned %s not "	\
Packit 6c4009
	      "%s (%s)\n", s, fstr, efstr, mode_name);		\
Packit 6c4009
      if (ROUNDING_TESTS (FTYPE, rnd_mode) || exact->FSUF)	\
Packit 6c4009
	result = 1;						\
Packit 6c4009
      else							\
Packit 6c4009
	printf ("ignoring this inexact result\n");		\
Packit 6c4009
    }								\
Packit 6c4009
  else								\
Packit 6c4009
    {								\
Packit 6c4009
      if (FE_INEXACT != 0)					\
Packit 6c4009
	{							\
Packit 6c4009
	  bool inexact_raised = fetestexcept (FE_INEXACT) != 0;	\
Packit 6c4009
	  if (inexact_raised != !exact->FSUF)			\
Packit 6c4009
	    {							\
Packit 6c4009
	      printf (FNPFXS "to" #FSUF				\
Packit 6c4009
		      " (" STRM ") inexact %d "			\
Packit 6c4009
		      "not %d\n", s, inexact_raised,		\
Packit 6c4009
		      !exact->FSUF);				\
Packit 6c4009
	      if (EXCEPTION_TESTS (FTYPE))			\
Packit 6c4009
		result = 1;					\
Packit 6c4009
	      else						\
Packit 6c4009
		printf ("ignoring this exception error\n");	\
Packit 6c4009
	    }							\
Packit 6c4009
	}							\
Packit 6c4009
      if (FE_OVERFLOW != 0)					\
Packit 6c4009
	{							\
Packit 6c4009
	  bool overflow_raised					\
Packit 6c4009
	    = fetestexcept (FE_OVERFLOW) != 0;			\
Packit 6c4009
	  if (overflow_raised != overflow->FSUF)		\
Packit 6c4009
	    {							\
Packit 6c4009
	      printf (FNPFXS "to" #FSUF				\
Packit 6c4009
		      " (" STRM ") overflow %d "		\
Packit 6c4009
		      "not %d\n", s, overflow_raised,		\
Packit 6c4009
		      overflow->FSUF);				\
Packit 6c4009
	      if (EXCEPTION_TESTS (FTYPE))			\
Packit 6c4009
		result = 1;					\
Packit 6c4009
	      else						\
Packit 6c4009
		printf ("ignoring this exception error\n");	\
Packit 6c4009
	    }							\
Packit 6c4009
	}							\
Packit 6c4009
    }								\
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
test_in_one_mode (const CHAR *s, const struct test_results *expected,
Packit 6c4009
		    const struct test_exactness *exact,
Packit 6c4009
		    const struct test_overflow *overflow,
Packit 6c4009
		    const char *mode_name, int rnd_mode)
Packit 6c4009
{
Packit 6c4009
  int result = 0;
Packit 6c4009
  GEN_TEST_STRTOD_FOREACH (GEN_ONE_TEST)
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static const struct fetestmodes
Packit 6c4009
  {
Packit 6c4009
  const char *mode_name;
Packit 6c4009
  int rnd_mode;
Packit 6c4009
  int rnd_i; /* Corresponding index into r array of struct test.  */
Packit 6c4009
  } modes[] = {
Packit 6c4009
    { "default rounding mode", FE_TONEAREST, 0 },
Packit 6c4009
#ifdef FE_DOWNWARD
Packit 6c4009
    { "FE_DOWNWARD", FE_DOWNWARD, 1 },
Packit 6c4009
#endif
Packit 6c4009
#ifdef FE_TOWARDZERO
Packit 6c4009
    { "FE_TOWARDZERO", FE_TOWARDZERO, 2 },
Packit 6c4009
#endif
Packit 6c4009
#ifdef FE_UPWARD
Packit 6c4009
    { "FE_UPWARD", FE_UPWARD, 3 },
Packit 6c4009
#endif
Packit 6c4009
    {}
Packit 6c4009
};
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
do_test (void)
Packit 6c4009
{
Packit 6c4009
  int save_round_mode __attribute__ ((unused)) = fegetround ();
Packit 6c4009
  int result = 0;
Packit 6c4009
  for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)
Packit 6c4009
    {
Packit 6c4009
      result |= test_in_one_mode (tests[i].s, &tests[i].r[modes[0].rnd_i],
Packit 6c4009
				  &tests[i].exact, &tests[i].o[modes[0].rnd_i],
Packit 6c4009
				  modes[0].mode_name, modes[0].rnd_mode);
Packit 6c4009
      for (const struct fetestmodes *m = &modes[1]; m->mode_name != NULL; m++)
Packit 6c4009
	{
Packit 6c4009
	  if (!fesetround (m->rnd_mode))
Packit 6c4009
	    {
Packit 6c4009
	      result |= test_in_one_mode (tests[i].s, &tests[i].r[m->rnd_i],
Packit 6c4009
					  &tests[i].exact,
Packit 6c4009
					  &tests[i].o[m->rnd_i], m->mode_name,
Packit 6c4009
					  m->rnd_mode);
Packit 6c4009
	      fesetround (save_round_mode);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
#define TEST_FUNCTION do_test ()
Packit 6c4009
#include "../test-skeleton.c"