mirror of https://gitee.com/Nocallback/glibc.git
21 changed files with 434 additions and 13 deletions
@ -0,0 +1 @@ |
|||
#define TININESS_AFTER_ROUNDING 1 |
|||
@ -0,0 +1 @@ |
|||
#define TININESS_AFTER_ROUNDING 1 |
|||
@ -0,0 +1 @@ |
|||
#define TININESS_AFTER_ROUNDING 1 |
|||
@ -0,0 +1 @@ |
|||
#define TININESS_AFTER_ROUNDING 1 |
|||
@ -0,0 +1 @@ |
|||
#define TININESS_AFTER_ROUNDING 1 |
|||
@ -0,0 +1,225 @@ |
|||
/* Test for strtod handling of arguments that may cause floating-point
|
|||
underflow. |
|||
Copyright (C) 2012 Free Software Foundation, Inc. |
|||
This file is part of the GNU C Library. |
|||
|
|||
The GNU C Library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
The GNU C Library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with the GNU C Library; if not, see |
|||
<http://www.gnu.org/licenses/>. */
|
|||
|
|||
#include <errno.h> |
|||
#include <fenv.h> |
|||
#include <float.h> |
|||
#include <stdbool.h> |
|||
#include <stdio.h> |
|||
#include <stdlib.h> |
|||
#include <tininess.h> |
|||
|
|||
enum underflow_case |
|||
{ |
|||
/* Result is exact or outside the subnormal range. */ |
|||
UNDERFLOW_NONE, |
|||
/* Result has magnitude at most half way between the largest
|
|||
subnormal value and the smallest positive normal value, and is |
|||
not exact, so underflows in all rounding modes and independent |
|||
of how tininess is detected. */ |
|||
UNDERFLOW_ALWAYS, |
|||
/* Result is positive, with magnitude larger than half way between
|
|||
the largest subnormal value and the least positive normal |
|||
value, but would underflow when rounded to nearest to normal |
|||
precision, so underflows after rounding in all modes except |
|||
rounding upward. */ |
|||
UNDERFLOW_EXCEPT_UPWARD, |
|||
/* Likewise, for a negative result, underflowing after rounding
|
|||
except when rounding downward. */ |
|||
UNDERFLOW_EXCEPT_DOWNWARD, |
|||
/* Result is positive, with magnitude at least three quarters of
|
|||
the way from the largest subnormal value to the smallest |
|||
positive normal value, so underflows after rounding only when |
|||
rounding downward or toward zero. */ |
|||
UNDERFLOW_ONLY_DOWNWARD_ZERO, |
|||
/* Likewise, for a negative result, underflowing after rounding
|
|||
only when rounding upward or toward zero. */ |
|||
UNDERFLOW_ONLY_UPWARD_ZERO, |
|||
}; |
|||
|
|||
struct test |
|||
{ |
|||
const char *s; |
|||
enum underflow_case c; |
|||
}; |
|||
|
|||
static const struct test tests[] = |
|||
{ |
|||
{ "0x1p-1022", UNDERFLOW_NONE }, |
|||
{ "-0x1p-1022", UNDERFLOW_NONE }, |
|||
{ "0x0p-10000000000000000000000000", UNDERFLOW_NONE }, |
|||
{ "-0x0p-10000000000000000000000000", UNDERFLOW_NONE }, |
|||
{ "0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS }, |
|||
{ "-0x1p-10000000000000000000000000", UNDERFLOW_ALWAYS }, |
|||
{ "0x1.000000000000000000001p-1022", UNDERFLOW_NONE }, |
|||
{ "-0x1.000000000000000000001p-1022", UNDERFLOW_NONE }, |
|||
{ "0x1p-1075", UNDERFLOW_ALWAYS }, |
|||
{ "-0x1p-1075", UNDERFLOW_ALWAYS }, |
|||
{ "0x1p-1023", UNDERFLOW_NONE }, |
|||
{ "-0x1p-1023", UNDERFLOW_NONE }, |
|||
{ "0x1p-1074", UNDERFLOW_NONE }, |
|||
{ "-0x1p-1074", UNDERFLOW_NONE }, |
|||
{ "0x1.ffffffffffffep-1023", UNDERFLOW_NONE }, |
|||
{ "-0x1.ffffffffffffep-1023", UNDERFLOW_NONE }, |
|||
{ "0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS }, |
|||
{ "-0x1.fffffffffffffp-1023", UNDERFLOW_ALWAYS }, |
|||
{ "0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_UPWARD }, |
|||
{ "-0x1.fffffffffffff0001p-1023", UNDERFLOW_EXCEPT_DOWNWARD }, |
|||
{ "0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_UPWARD }, |
|||
{ "-0x1.fffffffffffff7fffp-1023", UNDERFLOW_EXCEPT_DOWNWARD }, |
|||
{ "0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO }, |
|||
{ "-0x1.fffffffffffff8p-1023", UNDERFLOW_ONLY_UPWARD_ZERO }, |
|||
{ "0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_DOWNWARD_ZERO }, |
|||
{ "-0x1.fffffffffffffffffp-1023", UNDERFLOW_ONLY_UPWARD_ZERO }, |
|||
}; |
|||
|
|||
/* Return whether to expect underflow from a particular testcase, in a
|
|||
given rounding mode. */ |
|||
|
|||
static bool |
|||
expect_underflow (enum underflow_case c, int rm) |
|||
{ |
|||
if (c == UNDERFLOW_NONE) |
|||
return false; |
|||
if (c == UNDERFLOW_ALWAYS) |
|||
return true; |
|||
if (TININESS_AFTER_ROUNDING) |
|||
{ |
|||
switch (rm) |
|||
{ |
|||
#ifdef FE_DOWNWARD |
|||
case FE_DOWNWARD: |
|||
return (c == UNDERFLOW_EXCEPT_UPWARD |
|||
|| c == UNDERFLOW_ONLY_DOWNWARD_ZERO); |
|||
#endif |
|||
|
|||
#ifdef FE_TOWARDZERO |
|||
case FE_TOWARDZERO: |
|||
return true; |
|||
#endif |
|||
|
|||
#ifdef FE_UPWARD |
|||
case FE_UPWARD: |
|||
return (c == UNDERFLOW_EXCEPT_DOWNWARD |
|||
|| c == UNDERFLOW_ONLY_UPWARD_ZERO); |
|||
#endif |
|||
|
|||
default: |
|||
return (c == UNDERFLOW_EXCEPT_UPWARD |
|||
|| c == UNDERFLOW_EXCEPT_DOWNWARD); |
|||
} |
|||
} |
|||
else |
|||
return true; |
|||
} |
|||
|
|||
static bool support_underflow_exception = false; |
|||
volatile double d = DBL_MIN; |
|||
volatile double dd; |
|||
|
|||
static int |
|||
test_in_one_mode (const char *s, enum underflow_case c, int rm, |
|||
const char *mode_name) |
|||
{ |
|||
int result = 0; |
|||
feclearexcept (FE_ALL_EXCEPT); |
|||
errno = 0; |
|||
double d = strtod (s, NULL); |
|||
int got_errno = errno; |
|||
#ifdef FE_UNDERFLOW |
|||
bool got_fe_underflow = fetestexcept (FE_UNDERFLOW) != 0; |
|||
#else |
|||
bool got_fe_underflow = false; |
|||
#endif |
|||
printf ("strtod (%s) (%s) returned %a, errno = %d, %sunderflow exception\n", |
|||
s, mode_name, d, got_errno, got_fe_underflow ? "" : "no "); |
|||
bool this_expect_underflow = expect_underflow (c, rm); |
|||
if (got_errno != 0 && got_errno != ERANGE) |
|||
{ |
|||
puts ("FAIL: errno neither 0 nor ERANGE"); |
|||
result = 1; |
|||
} |
|||
else if (this_expect_underflow != (errno == ERANGE)) |
|||
{ |
|||
puts ("FAIL: underflow from errno differs from expectations"); |
|||
result = 1; |
|||
} |
|||
if (support_underflow_exception && got_fe_underflow != this_expect_underflow) |
|||
{ |
|||
puts ("FAIL: underflow from exceptions differs from expectations"); |
|||
result = 1; |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
static int |
|||
do_test (void) |
|||
{ |
|||
int save_round_mode = fegetround (); |
|||
int result = 0; |
|||
#ifdef FE_TONEAREST |
|||
const int fe_tonearest = FE_TONEAREST; |
|||
#else |
|||
const int fe_tonearest = 0; |
|||
# if defined FE_DOWNWARD || defined FE_TOWARDZERO || defined FE_UPWARD |
|||
# error "FE_TONEAREST not defined, but another rounding mode is" |
|||
# endif |
|||
#endif |
|||
#ifdef FE_UNDERFLOW |
|||
feclearexcept (FE_ALL_EXCEPT); |
|||
dd = d * d; |
|||
if (fetestexcept (FE_UNDERFLOW)) |
|||
support_underflow_exception = true; |
|||
else |
|||
puts ("underflow exception not supported at runtime, only testing errno"); |
|||
#endif |
|||
for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++) |
|||
{ |
|||
result |= test_in_one_mode (tests[i].s, tests[i].c, fe_tonearest, |
|||
"default rounding mode"); |
|||
#ifdef FE_DOWNWARD |
|||
if (!fesetround (FE_DOWNWARD)) |
|||
{ |
|||
result |= test_in_one_mode (tests[i].s, tests[i].c, FE_DOWNWARD, |
|||
"FE_DOWNWARD"); |
|||
fesetround (save_round_mode); |
|||
} |
|||
#endif |
|||
#ifdef FE_TOWARDZERO |
|||
if (!fesetround (FE_TOWARDZERO)) |
|||
{ |
|||
result |= test_in_one_mode (tests[i].s, tests[i].c, FE_TOWARDZERO, |
|||
"FE_TOWARDZERO"); |
|||
fesetround (save_round_mode); |
|||
} |
|||
#endif |
|||
#ifdef FE_UPWARD |
|||
if (!fesetround (FE_UPWARD)) |
|||
{ |
|||
result |= test_in_one_mode (tests[i].s, tests[i].c, FE_UPWARD, |
|||
"FE_UPWARD"); |
|||
fesetround (save_round_mode); |
|||
} |
|||
#endif |
|||
} |
|||
return result; |
|||
} |
|||
|
|||
#define TEST_FUNCTION do_test () |
|||
#include "../test-skeleton.c" |
|||
@ -0,0 +1,69 @@ |
|||
/* Test that tininess.h is correct for this architecture.
|
|||
Copyright (C) 2012 Free Software Foundation, Inc. |
|||
This file is part of the GNU C Library. |
|||
|
|||
The GNU C Library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
The GNU C Library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with the GNU C Library; if not, see |
|||
<http://www.gnu.org/licenses/>. */
|
|||
|
|||
#include <fenv.h> |
|||
#include <float.h> |
|||
#include <stdio.h> |
|||
#include <tininess.h> |
|||
|
|||
volatile float a = 0x1.fffp-126; |
|||
volatile float b = 0x1.0008p-1; |
|||
volatile float c; |
|||
volatile float m = FLT_MIN; |
|||
volatile float mm; |
|||
|
|||
static int |
|||
do_test (void) |
|||
{ |
|||
int result = 0; |
|||
#ifdef FE_UNDERFLOW |
|||
feclearexcept (FE_ALL_EXCEPT); |
|||
mm = m * m; |
|||
if (!fetestexcept (FE_UNDERFLOW)) |
|||
{ |
|||
puts ("underflow exception not supported at runtime, cannot test"); |
|||
return 0; |
|||
} |
|||
feclearexcept (FE_ALL_EXCEPT); |
|||
c = a * b; |
|||
if (fetestexcept (FE_UNDERFLOW)) |
|||
{ |
|||
if (TININESS_AFTER_ROUNDING) |
|||
{ |
|||
puts ("tininess.h says after rounding, " |
|||
"but detected before rounding"); |
|||
result = 1; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (!TININESS_AFTER_ROUNDING) |
|||
{ |
|||
puts ("tininess.h says before rounding, " |
|||
"but detected after rounding"); |
|||
result = 1; |
|||
} |
|||
} |
|||
#else |
|||
puts ("underflow exception not supported at compile time, cannot test"); |
|||
#endif |
|||
return result; |
|||
} |
|||
|
|||
#define TEST_FUNCTION do_test () |
|||
#include "../test-skeleton.c" |
|||
@ -0,0 +1,33 @@ |
|||
/* Specify architecture-specific rules for determining tininess of
|
|||
floating-point results. Generic version. |
|||
Copyright (C) 2012 Free Software Foundation, Inc. |
|||
This file is part of the GNU C Library. |
|||
|
|||
The GNU C Library is free software; you can redistribute it and/or |
|||
modify it under the terms of the GNU Lesser General Public |
|||
License as published by the Free Software Foundation; either |
|||
version 2.1 of the License, or (at your option) any later version. |
|||
|
|||
The GNU C Library is distributed in the hope that it will be useful, |
|||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|||
Lesser General Public License for more details. |
|||
|
|||
You should have received a copy of the GNU Lesser General Public |
|||
License along with the GNU C Library; if not, see |
|||
<http://www.gnu.org/licenses/>. */
|
|||
|
|||
#ifndef _TININESS_H |
|||
#define _TININESS_H 1 |
|||
|
|||
/* Under IEEE 754, an architecture may determine tininess of
|
|||
floating-point results either "before rounding" or "after |
|||
rounding", but must do so in the same way for all operations |
|||
returning binary results. Define TININESS_AFTER_ROUNDING to 1 for |
|||
"after rounding" architectures, 0 for "before rounding" |
|||
architectures. The test stdlib/tst-tininess will fail if the |
|||
definition is incorrect. */ |
|||
|
|||
#define TININESS_AFTER_ROUNDING 0 |
|||
|
|||
#endif /* tininess.h */ |
|||
@ -0,0 +1 @@ |
|||
#define TININESS_AFTER_ROUNDING 1 |
|||
@ -0,0 +1 @@ |
|||
#define TININESS_AFTER_ROUNDING 1 |
|||
@ -0,0 +1 @@ |
|||
#define TININESS_AFTER_ROUNDING 1 |
|||
Loading…
Reference in new issue