mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-21 12:30:06 +00:00
Fix strtod handling of underflow (bug 14047).
This commit is contained in:
parent
e5088dc687
commit
2a27fd6dae
21
ChangeLog
21
ChangeLog
@ -1,3 +1,24 @@
|
||||
2012-10-30 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #14047]
|
||||
* sysdeps/generic/tininess.h: New file.
|
||||
* sysdeps/i386/tininess.h: Likewise.
|
||||
* sysdeps/sh/tininess.h: Likewise.
|
||||
* sysdeps/x86_64/tininess.h: Likewise.
|
||||
* stdlib/tst-strtod-underflow.c: Likewise.
|
||||
* stdlib/tst-tininess.c: Likewise.
|
||||
* stdlib/strtod_l.c: Include <tininess.h>.
|
||||
(round_and_return): Do not set errno for exact underflow cases.
|
||||
Force an underflow exception when setting errno for underflow.
|
||||
Determine underflow based on rounding to normal precision if
|
||||
TININESS_AFTER_ROUNDING.
|
||||
* stdlib/tst-strtod.c (tests): Do not expect errno to be set to
|
||||
ERANGE for exact underflow cases.
|
||||
* stdlib/Makefile (tests): Add tst-tininess and
|
||||
tst-strtod-underflow.
|
||||
($(objpfx)tst-tininess): Use $(link-libm).
|
||||
($(objpfx)tst-strtod-underflow): Likewise.
|
||||
|
||||
2012-10-30 Andreas Jaeger <aj@suse.de>
|
||||
|
||||
[BZ#14767]
|
||||
|
14
NEWS
14
NEWS
@ -11,13 +11,13 @@ Version 2.17
|
||||
|
||||
1349, 3479, 5044, 5298, 5400, 6530, 6778, 6808, 9685, 9914, 10014, 10038,
|
||||
10631, 11438, 11607, 12140, 13412, 13542, 13601, 13629, 13679, 13696,
|
||||
13717, 13741, 13939, 13966, 14042, 14090, 14150, 14151, 14154, 14157,
|
||||
14166, 14173, 14195, 14237, 14251, 14252, 14283, 14298, 14303, 14307,
|
||||
14328, 14331, 14336, 14337, 14347, 14349, 14376, 14417, 14459, 14476,
|
||||
14477, 14505, 14510, 14516, 14518, 14519, 14530, 14532, 14538, 14543,
|
||||
14544, 14545, 14557, 14562, 14568, 14576, 14579, 14583, 14587, 14602,
|
||||
14621, 14638, 14645, 14648, 14652, 14660, 14661, 14683, 14694, 14716,
|
||||
14743, 14767.
|
||||
13717, 13741, 13939, 13966, 14042, 14047, 14090, 14150, 14151, 14154,
|
||||
14157, 14166, 14173, 14195, 14237, 14251, 14252, 14283, 14298, 14303,
|
||||
14307, 14328, 14331, 14336, 14337, 14347, 14349, 14376, 14417, 14459,
|
||||
14476, 14477, 14505, 14510, 14516, 14518, 14519, 14530, 14532, 14538,
|
||||
14543, 14544, 14545, 14557, 14562, 14568, 14576, 14579, 14583, 14587,
|
||||
14602, 14621, 14638, 14645, 14648, 14652, 14660, 14661, 14683, 14694,
|
||||
14716, 14743, 14767.
|
||||
|
||||
* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
|
||||
Optimized versions of memcpy, memset, and memcmp added for System z10 and
|
||||
|
@ -1,3 +1,8 @@
|
||||
2012-10-30 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #14047]
|
||||
* sysdeps/alpha/tininess.h: New file.
|
||||
|
||||
2012-10-19 Roland McGrath <roland@hack.frob.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/alpha/nptl/libc.abilist
|
||||
|
@ -1,3 +1,8 @@
|
||||
2012-10-30 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #14047]
|
||||
* sysdeps/am33/tininess.h: New file.
|
||||
|
||||
2012-10-09 Roland McGrath <roland@hack.frob.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/am33/configure: Regenerated.
|
||||
|
@ -1,3 +1,8 @@
|
||||
2012-10-30 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #14047]
|
||||
* sysdeps/hppa/tininess.h: New file.
|
||||
|
||||
2012-10-29 Carlos O'Donell <carlos@systemhalted.org>
|
||||
|
||||
* sysdeps/unix/sysv/linux/hppa/sysdep.h (ENTRY): Add cfi_startproc.
|
||||
|
@ -1,3 +1,8 @@
|
||||
2012-10-30 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #14047]
|
||||
* sysdeps/ia64/tininess.h: New file.
|
||||
|
||||
2012-10-25 Andreas Jaeger <aj@suse.de>
|
||||
|
||||
* sysdeps/unix/sysv/linux/ia64/bits/fcntl.h: Remove all
|
||||
|
@ -1,3 +1,8 @@
|
||||
2012-10-30 Joseph Myers <joseph@codesourcery.com>
|
||||
|
||||
[BZ #14047]
|
||||
* sysdeps/mips/tininess.h: New file.
|
||||
|
||||
2012-10-29 Steve Ellcey <sellcey@mips.com>
|
||||
|
||||
* sysdeps/unix/sysv/linux/mips/mips32/Makefile: Remove.
|
||||
|
1
ports/sysdeps/alpha/tininess.h
Normal file
1
ports/sysdeps/alpha/tininess.h
Normal file
@ -0,0 +1 @@
|
||||
#define TININESS_AFTER_ROUNDING 1
|
1
ports/sysdeps/am33/tininess.h
Normal file
1
ports/sysdeps/am33/tininess.h
Normal file
@ -0,0 +1 @@
|
||||
#define TININESS_AFTER_ROUNDING 1
|
1
ports/sysdeps/hppa/tininess.h
Normal file
1
ports/sysdeps/hppa/tininess.h
Normal file
@ -0,0 +1 @@
|
||||
#define TININESS_AFTER_ROUNDING 1
|
1
ports/sysdeps/ia64/tininess.h
Normal file
1
ports/sysdeps/ia64/tininess.h
Normal file
@ -0,0 +1 @@
|
||||
#define TININESS_AFTER_ROUNDING 1
|
1
ports/sysdeps/mips/tininess.h
Normal file
1
ports/sysdeps/mips/tininess.h
Normal file
@ -0,0 +1 @@
|
||||
#define TININESS_AFTER_ROUNDING 1
|
@ -69,7 +69,8 @@ tests := tst-strtol tst-strtod testmb testrand testsort testdiv \
|
||||
tst-makecontext tst-strtod4 tst-strtod5 tst-qsort2 \
|
||||
tst-makecontext2 tst-strtod6 tst-unsetenv1 \
|
||||
tst-makecontext3 bug-getcontext bug-fmtmsg1 \
|
||||
tst-secure-getenv tst-strtod-overflow tst-strtod-round
|
||||
tst-secure-getenv tst-strtod-overflow tst-strtod-round \
|
||||
tst-tininess tst-strtod-underflow
|
||||
tests-static := tst-secure-getenv
|
||||
|
||||
include ../Makeconfig
|
||||
@ -151,3 +152,5 @@ link-libm = $(common-objpfx)math/libm.a
|
||||
endif
|
||||
$(objpfx)bug-getcontext: $(link-libm)
|
||||
$(objpfx)tst-strtod-round: $(link-libm)
|
||||
$(objpfx)tst-tininess: $(link-libm)
|
||||
$(objpfx)tst-strtod-underflow: $(link-libm)
|
||||
|
@ -62,6 +62,7 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **,
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <rounding-mode.h>
|
||||
#include <tininess.h>
|
||||
|
||||
/* The gmp headers need some configuration frobs. */
|
||||
#define HAVE_ALLOCA 1
|
||||
@ -209,12 +210,15 @@ static FLOAT
|
||||
round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
|
||||
mp_limb_t round_limb, mp_size_t round_bit, int more_bits)
|
||||
{
|
||||
int mode = get_rounding_mode ();
|
||||
|
||||
if (exponent < MIN_EXP - 1)
|
||||
{
|
||||
if (exponent < MIN_EXP - 1 - MANT_DIG)
|
||||
return underflow_value (negative);
|
||||
|
||||
mp_size_t shift = MIN_EXP - 1 - exponent;
|
||||
bool is_tiny = true;
|
||||
|
||||
more_bits |= (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0;
|
||||
if (shift == MANT_DIG)
|
||||
@ -248,6 +252,33 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
|
||||
}
|
||||
else if (shift > 0)
|
||||
{
|
||||
if (TININESS_AFTER_ROUNDING && shift == 1)
|
||||
{
|
||||
/* Whether the result counts as tiny depends on whether,
|
||||
after rounding to the normal precision, it still has
|
||||
a subnormal exponent. */
|
||||
mp_limb_t retval_normal[RETURN_LIMB_SIZE];
|
||||
if (round_away (negative,
|
||||
(retval[0] & 1) != 0,
|
||||
(round_limb
|
||||
& (((mp_limb_t) 1) << round_bit)) != 0,
|
||||
(more_bits
|
||||
|| ((round_limb
|
||||
& ((((mp_limb_t) 1) << round_bit) - 1))
|
||||
!= 0)),
|
||||
mode))
|
||||
{
|
||||
mp_limb_t cy = __mpn_add_1 (retval_normal, retval,
|
||||
RETURN_LIMB_SIZE, 1);
|
||||
|
||||
if (((MANT_DIG % BITS_PER_MP_LIMB) == 0 && cy) ||
|
||||
((MANT_DIG % BITS_PER_MP_LIMB) != 0 &&
|
||||
((retval_normal[RETURN_LIMB_SIZE - 1]
|
||||
& (((mp_limb_t) 1) << (MANT_DIG % BITS_PER_MP_LIMB)))
|
||||
!= 0)))
|
||||
is_tiny = false;
|
||||
}
|
||||
}
|
||||
round_limb = retval[0];
|
||||
round_bit = shift - 1;
|
||||
(void) __mpn_rshift (retval, retval, RETURN_LIMB_SIZE, shift);
|
||||
@ -259,14 +290,20 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
|
||||
# define DENORM_EXP (MIN_EXP - 2)
|
||||
#endif
|
||||
exponent = DENORM_EXP;
|
||||
__set_errno (ERANGE);
|
||||
if (is_tiny
|
||||
&& ((round_limb & (((mp_limb_t) 1) << round_bit)) != 0
|
||||
|| more_bits
|
||||
|| (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0))
|
||||
{
|
||||
__set_errno (ERANGE);
|
||||
volatile FLOAT force_underflow_exception = MIN_VALUE * MIN_VALUE;
|
||||
(void) force_underflow_exception;
|
||||
}
|
||||
}
|
||||
|
||||
if (exponent > MAX_EXP)
|
||||
goto overflow;
|
||||
|
||||
int mode = get_rounding_mode ();
|
||||
|
||||
if (round_away (negative,
|
||||
(retval[0] & 1) != 0,
|
||||
(round_limb & (((mp_limb_t) 1) << round_bit)) != 0,
|
||||
|
225
stdlib/tst-strtod-underflow.c
Normal file
225
stdlib/tst-strtod-underflow.c
Normal file
@ -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"
|
@ -60,10 +60,10 @@ static const struct ltest tests[] =
|
||||
{ "0x00.0014p19", 160.0, '\0', 0 },
|
||||
{ "0x1p-1023",
|
||||
1.11253692925360069154511635866620203210960799023116591527666e-308,
|
||||
'\0', ERANGE },
|
||||
'\0', 0 },
|
||||
{ "0x0.8p-1022",
|
||||
1.11253692925360069154511635866620203210960799023116591527666e-308,
|
||||
'\0', ERANGE },
|
||||
'\0', 0 },
|
||||
{ "Inf", HUGE_VAL, '\0', 0 },
|
||||
{ "-Inf", -HUGE_VAL, '\0', 0 },
|
||||
{ "+InFiNiTy", HUGE_VAL, '\0', 0 },
|
||||
|
69
stdlib/tst-tininess.c
Normal file
69
stdlib/tst-tininess.c
Normal file
@ -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"
|
33
sysdeps/generic/tininess.h
Normal file
33
sysdeps/generic/tininess.h
Normal file
@ -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 */
|
1
sysdeps/i386/tininess.h
Normal file
1
sysdeps/i386/tininess.h
Normal file
@ -0,0 +1 @@
|
||||
#define TININESS_AFTER_ROUNDING 1
|
1
sysdeps/sh/tininess.h
Normal file
1
sysdeps/sh/tininess.h
Normal file
@ -0,0 +1 @@
|
||||
#define TININESS_AFTER_ROUNDING 1
|
1
sysdeps/x86_64/tininess.h
Normal file
1
sysdeps/x86_64/tininess.h
Normal file
@ -0,0 +1 @@
|
||||
#define TININESS_AFTER_ROUNDING 1
|
Loading…
Reference in New Issue
Block a user