mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-22 19:00:07 +00:00
Make strtod respect the rounding mode (bug 14518).
This commit is contained in:
parent
19fcedd5fc
commit
6c9b0f6826
27
ChangeLog
27
ChangeLog
@ -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
2
NEWS
@ -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
65
include/rounding-mode.h
Normal 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 */
|
@ -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
|
||||
|
@ -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:
|
||||
|
42
ports/sysdeps/arm/get-rounding-mode.h
Normal file
42
ports/sysdeps/arm/get-rounding-mode.h
Normal 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 */
|
35
ports/sysdeps/powerpc/nofpu/get-rounding-mode.h
Normal file
35
ports/sysdeps/powerpc/nofpu/get-rounding-mode.h
Normal 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 */
|
@ -150,3 +150,4 @@ else
|
||||
link-libm = $(common-objpfx)math/libm.a
|
||||
endif
|
||||
$(objpfx)bug-getcontext: $(link-libm)
|
||||
$(objpfx)tst-strtod-round: $(link-libm)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
124
sysdeps/generic/get-rounding-mode.h
Normal file
124
sysdeps/generic/get-rounding-mode.h
Normal 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 */
|
37
sysdeps/s390/fpu/get-rounding-mode.h
Normal file
37
sysdeps/s390/fpu/get-rounding-mode.h
Normal 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 */
|
Loading…
Reference in New Issue
Block a user