Make strtod respect the rounding mode (bug 14518).

This commit is contained in:
Joseph Myers 2012-09-12 23:36:19 +00:00
parent 19fcedd5fc
commit 6c9b0f6826
12 changed files with 491 additions and 53 deletions

View File

@ -1,3 +1,30 @@
2012-09-12 Joseph Myers <joseph@codesourcery.com>
[BZ #14518]
* include/rounding-mode.h: New file.
* sysdeps/generic/get-rounding-mode.h: Likewise.
* sysdeps/s390/fpu/get-rounding-mode.h: Likewise.
* stdlib/strtod_l.c: Include <rounding-mode.h>.
(MAX_VALUE): New macro.
(MIN_VALUE): Likewise.
(overflow_value): New function.
(underflow_value): Likewise.
(round_and_return): Use overflow_value and underflow_value to
determine return values in overflow and underflow cases. Use
round_away to determine rounding depending on rounding mode.
(____STRTOF_INTERNAL): Use overflow_value and underflow_value to
determine return values in overflow and underflow cases.
* stdlib/tst-strtod-round.c: Include <fenv.h>.
(struct test_results): New structure.
(struct test): Use struct test_results to store expected results
for all rounding modes.
(TEST): Include expected results for all rounding modes.
(test_in_one_mode): New function.
(do_test): Use test_in_one_mode to compute and check results.
Check results for all rounding modes.
* stdlib/Makefile ($(objpfx)tst-strtod-round): Depend on
$(link-libm).
2012-12-09 Allan McRae <allan@archlinux.org>
* sysdeps/i386/fpu/libm-test-ulps: Update

2
NEWS
View File

@ -13,7 +13,7 @@ Version 2.17
13542, 13717, 13696, 13939, 13966, 14042, 14090, 14166, 14150, 14151,
14154, 14157, 14166, 14173, 14195, 14237, 14252, 14283, 14298, 14303,
14307, 14328, 14331, 14336, 14337, 14347, 14349, 14459, 14476, 14505,
14510, 14516, 14519, 14532, 14538, 14544, 14545.
14510, 14516, 14518, 14519, 14532, 14538, 14544, 14545.
* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
Optimized versions of memcpy, memset, and memcmp added for System z10 and

65
include/rounding-mode.h Normal file
View File

@ -0,0 +1,65 @@
/* Handle floating-point rounding mode within libc.
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 _ROUNDING_MODE_H
#define _ROUNDING_MODE_H 1
#include <fenv.h>
#include <stdbool.h>
#include <stdlib.h>
/* Get the architecture-specific definition of how to determine the
rounding mode in libc. This header must also define the FE_*
macros for any standard rounding modes the architecture does not
have in <fenv.h>, to arbitrary distinct values. */
#include <get-rounding-mode.h>
/* Return true if a number should be rounded away from zero in
rounding mode MODE, false otherwise. NEGATIVE is true if the
number is negative, false otherwise. LAST_DIGIT_ODD is true if the
last digit of the truncated value (last bit for binary) is odd,
false otherwise. HALF_BIT is true if the number is at least half
way from the truncated value to the next value with the
least-significant digit in the same place, false otherwise.
MORE_BITS is true if the number is not exactly equal to the
truncated value or the half-way value, false otherwise. */
static inline bool
round_away (bool negative, bool last_digit_odd, bool half_bit, bool more_bits,
int mode)
{
switch (mode)
{
case FE_DOWNWARD:
return negative && (half_bit || more_bits);
case FE_TONEAREST:
return half_bit && (last_digit_odd || more_bits);
case FE_TOWARDZERO:
return false;
case FE_UPWARD:
return !negative && (half_bit || more_bits);
default:
abort ();
}
}
#endif /* rounding-mode.h */

View File

@ -1,3 +1,7 @@
2012-09-12 Joseph Myers <joseph@codesourcery.com>
* sysdeps/arm/get-rounding-mode.h: New file.
2012-08-27 Joseph Myers <joseph@codesourcery.com>
* sysdeps/unix/sysv/linux/arm/kernel-features.h

View File

@ -1,3 +1,7 @@
2012-09-12 Joseph Myers <joseph@codesourcery.com>
* sysdeps/powerpc/nofpu/get-rounding-mode.h: New file.
2012-07-25 Florian Weimer <fweimer@redhat.com>
* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/nptl/libc.abilist:

View File

@ -0,0 +1,42 @@
/* Determine floating-point rounding mode within libc. ARM 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 _ARM_GET_ROUNDING_MODE_H
#define _ARM_GET_ROUNDING_MODE_H 1
#include <arm-features.h>
#include <fenv.h>
#include <fpu_control.h>
/* Return the floating-point rounding mode. */
static inline int
get_rounding_mode (void)
{
if (ARM_HAVE_VFP)
{
fpu_control_t fc;
_FPU_GETCW (fc);
return fc & FE_TOWARDZERO;
}
else
return FE_TONEAREST;
}
#endif /* get-rounding-mode.h */

View File

@ -0,0 +1,35 @@
/* Determine floating-point rounding mode within libc. PowerPC
soft-float 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 _POWERPC_NOFPU_GET_ROUNDING_MODE_H
#define _POWERPC_NOFPU_GET_ROUNDING_MODE_H 1
#include <fenv.h>
#include "soft-supp.h"
/* Return the floating-point rounding mode. */
static inline int
get_rounding_mode (void)
{
return __sim_round_mode;
}
#endif /* get-rounding-mode.h */

View File

@ -150,3 +150,4 @@ else
link-libm = $(common-objpfx)math/libm.a
endif
$(objpfx)bug-getcontext: $(link-libm)
$(objpfx)tst-strtod-round: $(link-libm)

View File

@ -61,6 +61,7 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **,
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <rounding-mode.h>
/* The gmp headers need some configuration frobs. */
#define HAVE_ALLOCA 1
@ -126,6 +127,8 @@ extern unsigned long long int ____strtoull_l_internal (const char *, char **,
#define MIN_EXP PASTE(FLT,_MIN_EXP)
#define MAX_10_EXP PASTE(FLT,_MAX_10_EXP)
#define MIN_10_EXP PASTE(FLT,_MIN_10_EXP)
#define MAX_VALUE PASTE(FLT,_MAX)
#define MIN_VALUE PASTE(FLT,_MIN)
/* Extra macros required to get FLT expanded before the pasting. */
#define PASTE(a,b) PASTE1(a,b)
@ -172,6 +175,34 @@ extern const mp_limb_t _tens_in_limb[MAX_DIG_PER_LIMB + 1];
memcpy (dst, src, (dst##size = src##size) * sizeof (mp_limb_t))
/* Set errno and return an overflowing value with sign specified by
NEGATIVE. */
static FLOAT
overflow_value (int negative)
{
__set_errno (ERANGE);
#if FLT_EVAL_METHOD != 0
volatile
#endif
FLOAT result = (negative ? -MAX_VALUE : MAX_VALUE) * MAX_VALUE;
return result;
}
/* Set errno and return an underflowing value with sign specified by
NEGATIVE. */
static FLOAT
underflow_value (int negative)
{
__set_errno (ERANGE);
#if FLT_EVAL_METHOD != 0
volatile
#endif
FLOAT result = (negative ? -MIN_VALUE : MIN_VALUE) * MIN_VALUE;
return result;
}
/* Return a floating point number of the needed type according to the given
multi-precision number after possible rounding. */
static FLOAT
@ -181,10 +212,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
if (exponent < MIN_EXP - 1)
{
if (exponent < MIN_EXP - 1 - MANT_DIG)
{
__set_errno (ERANGE);
return negative ? -0.0 : 0.0;
}
return underflow_value (negative);
mp_size_t shift = MIN_EXP - 1 - exponent;
@ -237,9 +265,14 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
if (exponent > MAX_EXP)
goto overflow;
if ((round_limb & (((mp_limb_t) 1) << round_bit)) != 0
&& (more_bits || (retval[0] & 1) != 0
|| (round_limb & ((((mp_limb_t) 1) << round_bit) - 1)) != 0))
int mode = get_rounding_mode ();
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, retval, RETURN_LIMB_SIZE, 1);
@ -263,7 +296,7 @@ round_and_return (mp_limb_t *retval, intmax_t exponent, int negative,
if (exponent > MAX_EXP)
overflow:
return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
return overflow_value (negative);
return MPN2FLOAT (retval, exponent, negative);
}
@ -914,9 +947,9 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc)
else
{
/* Overflow or underflow. */
__set_errno (ERANGE);
result = (exp_negative ? (negative ? -0.0 : 0.0) :
negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL);
result = (exp_negative
? underflow_value (negative)
: overflow_value (negative));
}
/* Accept all following digits as part of the exponent. */
@ -1112,16 +1145,10 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc)
}
if (__builtin_expect (exponent > MAX_10_EXP + 1 - (intmax_t) int_no, 0))
{
__set_errno (ERANGE);
return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
}
return overflow_value (negative);
if (__builtin_expect (exponent < MIN_10_EXP - (DIG + 1), 0))
{
__set_errno (ERANGE);
return negative ? -0.0 : 0.0;
}
return underflow_value (negative);
if (int_no > 0)
{
@ -1182,10 +1209,7 @@ ____STRTOF_INTERNAL (nptr, endptr, group, loc)
/* Now we know the exponent of the number in base two.
Check it against the maximum possible exponent. */
if (__builtin_expect (bits > MAX_EXP, 0))
{
__set_errno (ERANGE);
return negative ? -FLOAT_HUGE_VAL : FLOAT_HUGE_VAL;
}
return overflow_value (negative);
/* We have already the first BITS bits of the result. Together with
the information whether more non-zero bits follow this is enough

View File

@ -17,6 +17,7 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <fenv.h>
#include <float.h>
#include <math.h>
#include <stdbool.h>
@ -24,21 +25,32 @@
#include <stdlib.h>
#include <string.h>
struct test {
const char *s;
struct test_results {
float f;
double d;
bool ld_ok;
long double ld;
};
struct test {
const char *s;
bool ld_ok;
struct test_results rd, rn, rz, ru;
};
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
# define TEST(s, fd, fn, fz, fu, dd, dn, dz, du, ld53d, ld53n, ld53z, ld53u, \
ld64id, ld64in, ld64iz, ld64iu, \
ld64md, ld64mn, ld64mz, ld64mu, \
ld106exact, ld106d, ld106n, ld106z, ld106u, \
ld113d, ld113n, ld113z, ld113u) \
{ s, fn, dn, true, ld53n }
{ \
s, \
true, \
{ fd, dd, ld53d }, \
{ fn, dn, ld53n }, \
{ fz, dz, ld53z }, \
{ fu, du, ld53u } \
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16381
/* This is for the Intel extended float format. */
# define TEST(s, fd, fn, fz, fu, dd, dn, dz, du, ld53d, ld53n, ld53z, ld53u, \
@ -46,7 +58,14 @@ struct test {
ld64md, ld64mn, ld64mz, ld64mu, \
ld106exact, ld106d, ld106n, ld106z, ld106u, \
ld113d, ld113n, ld113z, ld113u) \
{ s, fn, dn, true, ld64in }
{ \
s, \
true, \
{ fd, dd, ld64id }, \
{ fn, dn, ld64in }, \
{ fz, dz, ld64iz }, \
{ fu, du, ld64iu } \
}
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && LDBL_MIN_EXP == -16382
/* This is for the Motorola extended float format. */
# define TEST(s, fd, fn, fz, fu, dd, dn, dz, du, ld53d, ld53n, ld53z, ld53u, \
@ -54,21 +73,42 @@ struct test {
ld64md, ld64mn, ld64mz, ld64mu, \
ld106exact, ld106d, ld106n, ld106z, ld106u, \
ld113d, ld113n, ld113z, ld113u) \
{ s, fn, dn, true, ld64mn }
{ \
s, \
true, \
{ fd, dd, ld64md }, \
{ fn, dn, ld64mn }, \
{ fz, dz, ld64mz }, \
{ fu, du, ld64mu } \
}
#elif LDBL_MANT_DIG == 106 && LDBL_MAX_EXP == 1024
# define TEST(s, fd, fn, fz, fu, dd, dn, dz, du, ld53d, ld53n, ld53z, ld53u, \
ld64id, ld64in, ld64iz, ld64iu, \
ld64md, ld64mn, ld64mz, ld64mu, \
ld106exact, ld106d, ld106n, ld106z, ld106u, \
ld113d, ld113n, ld113z, ld113u) \
{ s, fn, dn, ld106exact, ld106n }
{ \
s, \
ld106exact, \
{ fd, dd, ld106d }, \
{ fn, dn, ld106n }, \
{ fz, dz, ld106z }, \
{ fu, du, ld106u } \
}
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
# define TEST(s, fd, fn, fz, fu, dd, dn, dz, du, ld53d, ld53n, ld53z, ld53u, \
ld64id, ld64in, ld64iz, ld64iu, \
ld64md, ld64mn, ld64mz, ld64mu, \
ld106exact, ld106d, ld106n, ld106z, ld106u, \
ld113d, ld113n, ld113z, ld113u) \
{ s, fn, dn, true, ld113n }
{ \
s, \
true, \
{ fd, dd, ld113d }, \
{ fn, dn, ld113n }, \
{ fz, dz, ld113z }, \
{ fu, du, ld113u } \
}
#else
# error "unknown long double format"
#endif
@ -6818,39 +6858,74 @@ static const struct test tests[] = {
-0x0p+0L),
};
static int
test_in_one_mode (const char *s, const struct test_results *expected,
bool ld_ok, const char *mode_name)
{
int result = 0;
float f = strtof (s, NULL);
double d = strtod (s, NULL);
long double ld = strtold (s, NULL);
if (f != expected->f
|| copysignf (1.0f, f) != copysignf (1.0f, expected->f))
{
printf ("strtof (%s) returned %a not %a (%s)\n", s, f,
expected->f, mode_name);
result = 1;
}
if (d != expected->d
|| copysign (1.0, d) != copysign (1.0, expected->d))
{
printf ("strtod (%s) returned %a not %a (%s)\n", s, d,
expected->d, mode_name);
result = 1;
}
if (ld != expected->ld
|| copysignl (1.0L, ld) != copysignl (1.0L, expected->ld))
{
printf ("strtold (%s) returned %La not %La (%s)\n", s, ld,
expected->ld, mode_name);
if (ld_ok)
result = 1;
else
printf ("ignoring this inexact long double result\n");
}
return result;
}
static int
do_test (void)
{
int save_round_mode = fegetround ();
int result = 0;
for (size_t i = 0; i < sizeof (tests) / sizeof (tests[0]); i++)
{
float f = strtof (tests[i].s, NULL);
double d = strtod (tests[i].s, NULL);
long double ld = strtold (tests[i].s, NULL);
if (f != tests[i].f
|| copysignf (1.0f, f) != copysignf (1.0f, tests[i].f))
result |= test_in_one_mode (tests[i].s, &tests[i].rn, tests[i].ld_ok,
"default rounding mode");
#ifdef FE_DOWNWARD
if (!fesetround (FE_DOWNWARD))
{
printf ("strtof (%s) returned %a not %a\n", tests[i].s, f,
tests[i].f);
result = 1;
result |= test_in_one_mode (tests[i].s, &tests[i].rd, tests[i].ld_ok,
"FE_DOWNWARD");
fesetround (save_round_mode);
}
if (d != tests[i].d
|| copysign (1.0, d) != copysign (1.0, tests[i].d))
#endif
#ifdef FE_TOWARDZERO
if (!fesetround (FE_TOWARDZERO))
{
printf ("strtod (%s) returned %a not %a\n", tests[i].s, d,
tests[i].d);
result = 1;
result |= test_in_one_mode (tests[i].s, &tests[i].rz, tests[i].ld_ok,
"FE_TOWARDZERO");
fesetround (save_round_mode);
}
if (ld != tests[i].ld
|| copysignl (1.0L, ld) != copysignl (1.0L, tests[i].ld))
#endif
#ifdef FE_UPWARD
if (!fesetround (FE_UPWARD))
{
printf ("strtold (%s) returned %La not %La\n", tests[i].s, ld,
tests[i].ld);
if (tests[i].ld_ok)
result = 1;
else
printf ("ignoring this inexact long double result\n");
result |= test_in_one_mode (tests[i].s, &tests[i].ru, tests[i].ld_ok,
"FE_UPWARD");
fesetround (save_round_mode);
}
#endif
}
return result;
}

View File

@ -0,0 +1,124 @@
/* Determine floating-point rounding mode within libc. 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 _GET_ROUNDING_MODE_H
#define _GET_ROUNDING_MODE_H 1
#include <fpu_control.h>
/* Define values for FE_* modes not defined for this architecture. */
#ifdef FE_DOWNWARD
# define ORIG_FE_DOWNWARD FE_DOWNWARD
#else
# define ORIG_FE_DOWNWARD 0
#endif
#ifdef FE_TONEAREST
# define ORIG_FE_TONEAREST FE_TONEAREST
#else
# define ORIG_FE_TONEAREST 0
#endif
#ifdef FE_TOWARDZERO
# define ORIG_FE_TOWARDZERO FE_TOWARDZERO
#else
# define ORIG_FE_TOWARDZERO 0
#endif
#ifdef FE_UPWARD
# define ORIG_FE_UPWARD FE_UPWARD
#else
# define ORIG_FE_UPWARD 0
#endif
#define FE_CONSTRUCT_DISTINCT_VALUE(X, Y, Z) \
((((X) & 1) | ((Y) & 2) | ((Z) & 4)) ^ 7)
#ifndef FE_DOWNWARD
# define FE_DOWNWARD FE_CONSTRUCT_DISTINCT_VALUE (ORIG_FE_TONEAREST, \
ORIG_FE_TOWARDZERO, \
ORIG_FE_UPWARD)
#endif
#ifndef FE_TONEAREST
# define FE_TONEAREST FE_CONSTRUCT_DISTINCT_VALUE (FE_DOWNWARD, \
ORIG_FE_TOWARDZERO, \
ORIG_FE_UPWARD)
#endif
#ifndef FE_TOWARDZERO
# define FE_TOWARDZERO FE_CONSTRUCT_DISTINCT_VALUE (FE_DOWNWARD, \
FE_TONEAREST, \
ORIG_FE_UPWARD)
#endif
#ifndef FE_UPWARD
# define FE_UPWARD FE_CONSTRUCT_DISTINCT_VALUE (FE_DOWNWARD, \
FE_TONEAREST, \
FE_TOWARDZERO)
#endif
/* Return the floating-point rounding mode. */
static inline int
get_rounding_mode (void)
{
#if (defined _FPU_RC_DOWN \
|| defined _FPU_RC_NEAREST \
|| defined _FPU_RC_ZERO \
|| defined _FPU_RC_UP)
fpu_control_t fc;
const fpu_control_t mask = (0
# ifdef _FPU_RC_DOWN
| _FPU_RC_DOWN
# endif
# ifdef _FPU_RC_NEAREST
| _FPU_RC_NEAREST
# endif
# ifdef _FPU_RC_ZERO
| _FPU_RC_ZERO
# endif
# ifdef _FPU_RC_UP
| _FPU_RC_UP
# endif
);
_FPU_GETCW (fc);
switch (fc & mask)
{
# ifdef _FPU_RC_DOWN
case _FPU_RC_DOWN:
return FE_DOWNWARD;
# endif
# ifdef _FPU_RC_NEAREST
case _FPU_RC_NEAREST:
return FE_TONEAREST;
# endif
# ifdef _FPU_RC_ZERO
case _FPU_RC_ZERO:
return FE_TOWARDZERO;
# endif
# ifdef _FPU_RC_UP
case _FPU_RC_UP:
return FE_UPWARD;
# endif
default:
abort ();
}
#else
return FE_TONEAREST;
#endif
}
#endif /* get-rounding-mode.h */

View File

@ -0,0 +1,37 @@
/* Determine floating-point rounding mode within libc. S/390 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 _S390_GET_ROUNDING_MODE_H
#define _S390_GET_ROUNDING_MODE_H 1
#include <fenv.h>
#include <fenv_libc.h>
#include <fpu_control.h>
/* Return the floating-point rounding mode. */
static inline int
get_rounding_mode (void)
{
fpu_control_t fc;
_FPU_GETCW (fc);
return fc & FPC_RM_MASK;
}
#endif /* get-rounding-mode.h */