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

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