Blame stdlib/tst-strtod-underflow.c

Packit Service 82fcde
/* Test for strtod handling of arguments that may cause floating-point
Packit Service 82fcde
   underflow.
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
#include <errno.h>
Packit Service 82fcde
#include <fenv.h>
Packit Service 82fcde
#include <float.h>
Packit Service 82fcde
#include <stdbool.h>
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <tininess.h>
Packit Service 82fcde
Packit Service 82fcde
enum underflow_case
Packit Service 82fcde
  {
Packit Service 82fcde
    /* Result is exact or outside the subnormal range.  */
Packit Service 82fcde
    UNDERFLOW_NONE,
Packit Service 82fcde
    /* Result has magnitude at most half way between the largest
Packit Service 82fcde
       subnormal value and the smallest positive normal value, and is
Packit Service 82fcde
       not exact, so underflows in all rounding modes and independent
Packit Service 82fcde
       of how tininess is detected.  */
Packit Service 82fcde
    UNDERFLOW_ALWAYS,
Packit Service 82fcde
    /* Result is positive, with magnitude larger than half way between
Packit Service 82fcde
       the largest subnormal value and the least positive normal
Packit Service 82fcde
       value, but would underflow when rounded to nearest to normal
Packit Service 82fcde
       precision, so underflows after rounding in all modes except
Packit Service 82fcde
       rounding upward.  */
Packit Service 82fcde
    UNDERFLOW_EXCEPT_UPWARD,
Packit Service 82fcde
    /* Likewise, for a negative result, underflowing after rounding
Packit Service 82fcde
       except when rounding downward.  */
Packit Service 82fcde
    UNDERFLOW_EXCEPT_DOWNWARD,
Packit Service 82fcde
    /* Result is positive, with magnitude at least three quarters of
Packit Service 82fcde
       the way from the largest subnormal value to the smallest
Packit Service 82fcde
       positive normal value, so underflows after rounding only when
Packit Service 82fcde
       rounding downward or toward zero.  */
Packit Service 82fcde
    UNDERFLOW_ONLY_DOWNWARD_ZERO,
Packit Service 82fcde
    /* Likewise, for a negative result, underflowing after rounding
Packit Service 82fcde
       only when rounding upward or toward zero.  */
Packit Service 82fcde
    UNDERFLOW_ONLY_UPWARD_ZERO,
Packit Service 82fcde
  };
Packit Service 82fcde
Packit Service 82fcde
struct test
Packit Service 82fcde
{
Packit Service 82fcde
  const char *s;
Packit Service 82fcde
  enum underflow_case c;
Packit Service 82fcde
};
Packit Service 82fcde
Packit Service 82fcde
static const struct test tests[] =
Packit Service 82fcde
  {
Packit Service 82fcde
    { "0x1p-1022", UNDERFLOW_NONE },
Packit Service 82fcde
    { "-0x1p-1022", UNDERFLOW_NONE },
Packit Service 82fcde
    { "0x0p-10000000000000000000000000", UNDERFLOW_NONE },
Packit Service 82fcde
    { "-0x0p-10000000000000000000000000", UNDERFLOW_NONE },
Packit Service 82fcde
    { "0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS },
Packit Service 82fcde
    { "-0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS },
Packit Service 82fcde
    { "0x1.000000000000000000001p-1022", UNDERFLOW_NONE },
Packit Service 82fcde
    { "-0x1.000000000000000000001p-1022", UNDERFLOW_NONE },
Packit Service 82fcde
    { "0x1p-1075", UNDERFLOW_ALWAYS },
Packit Service 82fcde
    { "-0x1p-1075", UNDERFLOW_ALWAYS },
Packit Service 82fcde
    { "0x1p-1023", UNDERFLOW_NONE },
Packit Service 82fcde
    { "-0x1p-1023", UNDERFLOW_NONE },
Packit Service 82fcde
    { "0x1p-1074", UNDERFLOW_NONE },
Packit Service 82fcde
    { "-0x1p-1074", UNDERFLOW_NONE },
Packit Service 82fcde
    { "0x1.ffffffffffffep-1023", UNDERFLOW_NONE },
Packit Service 82fcde
    { "-0x1.ffffffffffffep-1023", UNDERFLOW_NONE },
Packit Service 82fcde
    { "0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS },
Packit Service 82fcde
    { "-0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS },
Packit Service 82fcde
    { "0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_UPWARD },
Packit Service 82fcde
    { "-0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_DOWNWARD },
Packit Service 82fcde
    { "0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_UPWARD },
Packit Service 82fcde
    { "-0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_DOWNWARD },
Packit Service 82fcde
    { "0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO },
Packit Service 82fcde
    { "-0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_UPWARD_ZERO },
Packit Service 82fcde
    { "0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO },
Packit Service 82fcde
    { "-0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_UPWARD_ZERO },
Packit Service 82fcde
  };
Packit Service 82fcde
Packit Service 82fcde
/* Return whether to expect underflow from a particular testcase, in a
Packit Service 82fcde
   given rounding mode.  */
Packit Service 82fcde
Packit Service 82fcde
static bool
Packit Service 82fcde
expect_underflow (enum underflow_case c, int rm)
Packit Service 82fcde
{
Packit Service 82fcde
  if (c == UNDERFLOW_NONE)
Packit Service 82fcde
    return false;
Packit Service 82fcde
  if (c == UNDERFLOW_ALWAYS)
Packit Service 82fcde
    return true;
Packit Service 82fcde
  if (TININESS_AFTER_ROUNDING)
Packit Service 82fcde
    {
Packit Service 82fcde
      switch (rm)
Packit Service 82fcde
	{
Packit Service 82fcde
#ifdef FE_DOWNWARD
Packit Service 82fcde
	case FE_DOWNWARD:
Packit Service 82fcde
	  return (c == UNDERFLOW_EXCEPT_UPWARD
Packit Service 82fcde
		  || c == UNDERFLOW_ONLY_DOWNWARD_ZERO);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifdef FE_TOWARDZERO
Packit Service 82fcde
	case FE_TOWARDZERO:
Packit Service 82fcde
	  return true;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#ifdef FE_UPWARD
Packit Service 82fcde
	case FE_UPWARD:
Packit Service 82fcde
	  return (c == UNDERFLOW_EXCEPT_DOWNWARD
Packit Service 82fcde
		  || c == UNDERFLOW_ONLY_UPWARD_ZERO);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
	default:
Packit Service 82fcde
	  return (c == UNDERFLOW_EXCEPT_UPWARD
Packit Service 82fcde
		  || c == UNDERFLOW_EXCEPT_DOWNWARD);
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    return true;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static bool support_underflow_exception = false;
Packit Service 82fcde
volatile double d = DBL_MIN;
Packit Service 82fcde
volatile double dd;
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
test_in_one_mode (const char *s, enum underflow_case c, int rm,
Packit Service 82fcde
		  const char *mode_name)
Packit Service 82fcde
{
Packit Service 82fcde
  int result = 0;
Packit Service 82fcde
  feclearexcept (FE_ALL_EXCEPT);
Packit Service 82fcde
  errno = 0;
Packit Service 82fcde
  double d = strtod (s, NULL);
Packit Service 82fcde
  int got_errno = errno;
Packit Service 82fcde
#ifdef FE_UNDERFLOW
Packit Service 82fcde
  bool got_fe_underflow = fetestexcept (FE_UNDERFLOW) != 0;
Packit Service 82fcde
#else
Packit Service 82fcde
  bool got_fe_underflow = false;
Packit Service 82fcde
#endif
Packit Service 82fcde
  printf ("strtod (%s) (%s) returned %a, errno = %d, %sunderflow exception\n",
Packit Service 82fcde
	  s, mode_name, d, got_errno, got_fe_underflow ? "" : "no ");
Packit Service 82fcde
  bool this_expect_underflow = expect_underflow (c, rm);
Packit Service 82fcde
  if (got_errno != 0 && got_errno != ERANGE)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("FAIL: errno neither 0 nor ERANGE");
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  else if (this_expect_underflow != (errno == ERANGE))
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("FAIL: underflow from errno differs from expectations");
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (support_underflow_exception && got_fe_underflow != this_expect_underflow)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("FAIL: underflow from exceptions differs from expectations");
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  return result;
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
#ifdef FE_TONEAREST
Packit Service 82fcde
  const int fe_tonearest = FE_TONEAREST;
Packit Service 82fcde
#else
Packit Service 82fcde
  const int fe_tonearest = 0;
Packit Service 82fcde
# if defined FE_DOWNWARD || defined FE_TOWARDZERO || defined FE_UPWARD
Packit Service 82fcde
#  error "FE_TONEAREST not defined, but another rounding mode is"
Packit Service 82fcde
# endif
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef FE_UNDERFLOW
Packit Service 82fcde
  feclearexcept (FE_ALL_EXCEPT);
Packit Service 82fcde
  dd = d * d;
Packit Service 82fcde
  if (fetestexcept (FE_UNDERFLOW))
Packit Service 82fcde
    support_underflow_exception = true;
Packit Service 82fcde
  else
Packit Service 82fcde
    puts ("underflow exception not supported at runtime, only testing errno");
Packit Service 82fcde
#endif
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].c, fe_tonearest,
Packit Service 82fcde
				  "default rounding mode");
Packit Service 82fcde
#ifdef FE_DOWNWARD
Packit Service 82fcde
      if (!fesetround (FE_DOWNWARD))
Packit Service 82fcde
	{
Packit Service 82fcde
	  result |= test_in_one_mode (tests[i].s, tests[i].c, FE_DOWNWARD,
Packit Service 82fcde
				      "FE_DOWNWARD");
Packit Service 82fcde
	  fesetround (save_round_mode);
Packit Service 82fcde
	}
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef FE_TOWARDZERO
Packit Service 82fcde
      if (!fesetround (FE_TOWARDZERO))
Packit Service 82fcde
	{
Packit Service 82fcde
	  result |= test_in_one_mode (tests[i].s, tests[i].c, FE_TOWARDZERO,
Packit Service 82fcde
				      "FE_TOWARDZERO");
Packit Service 82fcde
	  fesetround (save_round_mode);
Packit Service 82fcde
	}
Packit Service 82fcde
#endif
Packit Service 82fcde
#ifdef FE_UPWARD
Packit Service 82fcde
      if (!fesetround (FE_UPWARD))
Packit Service 82fcde
	{
Packit Service 82fcde
	  result |= test_in_one_mode (tests[i].s, tests[i].c, FE_UPWARD,
Packit Service 82fcde
				      "FE_UPWARD");
Packit Service 82fcde
	  fesetround (save_round_mode);
Packit Service 82fcde
	}
Packit Service 82fcde
#endif
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"