2006-09-17 07:26:24 +00:00
|
|
|
/* Round to long int long double floating-point values.
|
|
|
|
IBM extended format long double version.
|
2024-01-01 18:12:26 +00:00
|
|
|
Copyright (C) 2006-2024 Free Software Foundation, Inc.
|
2006-09-17 07:26:24 +00:00
|
|
|
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
|
2012-02-09 23:18:22 +00:00
|
|
|
License along with the GNU C Library; if not, see
|
Prefer https to http for gnu.org and fsf.org URLs
Also, change sources.redhat.com to sourceware.org.
This patch was automatically generated by running the following shell
script, which uses GNU sed, and which avoids modifying files imported
from upstream:
sed -ri '
s,(http|ftp)(://(.*\.)?(gnu|fsf|sourceware)\.org($|[^.]|\.[^a-z])),https\2,g
s,(http|ftp)(://(.*\.)?)sources\.redhat\.com($|[^.]|\.[^a-z]),https\2sourceware.org\4,g
' \
$(find $(git ls-files) -prune -type f \
! -name '*.po' \
! -name 'ChangeLog*' \
! -path COPYING ! -path COPYING.LIB \
! -path manual/fdl-1.3.texi ! -path manual/lgpl-2.1.texi \
! -path manual/texinfo.tex ! -path scripts/config.guess \
! -path scripts/config.sub ! -path scripts/install-sh \
! -path scripts/mkinstalldirs ! -path scripts/move-if-change \
! -path INSTALL ! -path locale/programs/charmap-kw.h \
! -path po/libc.pot ! -path sysdeps/gnu/errlist.c \
! '(' -name configure \
-execdir test -f configure.ac -o -f configure.in ';' ')' \
! '(' -name preconfigure \
-execdir test -f preconfigure.ac ';' ')' \
-print)
and then by running 'make dist-prepare' to regenerate files built
from the altered files, and then executing the following to cleanup:
chmod a+x sysdeps/unix/sysv/linux/riscv/configure
# Omit irrelevant whitespace and comment-only changes,
# perhaps from a slightly-different Autoconf version.
git checkout -f \
sysdeps/csky/configure \
sysdeps/hppa/configure \
sysdeps/riscv/configure \
sysdeps/unix/sysv/linux/csky/configure
# Omit changes that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/powerpc/powerpc64/ppc-mcount.S: trailing lines
git checkout -f \
sysdeps/powerpc/powerpc64/ppc-mcount.S \
sysdeps/unix/sysv/linux/s390/s390-64/syscall.S
# Omit change that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S: last line does not end in newline
git checkout -f sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S
2019-09-07 05:40:42 +00:00
|
|
|
<https://www.gnu.org/licenses/>. */
|
2006-09-17 07:26:24 +00:00
|
|
|
|
2006-01-28 00:15:15 +00:00
|
|
|
#include <math.h>
|
Clean up powerpc fegetround / __fegetround inlines.
The natural fix for some linknamespace test failures, where C90 libm
functions call C99 <fenv.h> functions, is to make fe* into weak
aliases for __fe* and call __fe* from within libm as needed.
To do this, the __fe* names need to be available for that purpose -
that is, they must not be used for something other than aliases of
fe*. On powerpc, however, __fegetround is an inline function in
fenv_libc.h, with no corresponding fegetround inline function;
fegetround has an equivalent macro expansion in bits/fenvinline.h, but
that is disabled if __NO_MATH_INLINES (which is defined for building
libm).
I see no need for that disabling; it's not even clear that
__NO_MATH_INLINES should affect <fenv.h>, and the results of
fegetround are completely defined so there is no semantic effect of
that disabling at all outside glibc. The x86 inline feraiseexcept is
conditioned on __USE_EXTERN_INLINES not __NO_MATH_INLINES (but that's
an inline function rather than a macro).
This patch removes the __NO_MATH_INLINES conditional on that
fegetround macro, so resulting in it being expanded inline inside
glibc. In turn, this means that direct calls to __fegetround from C99
functions in ldbl-128ibm can be changed to calls to fegetround, so
that nofpu fenv_libc.h files don't need to define __fegetround at all
and, by changing ldbl-128ibm files to use <fenv.h> not <fenv_libc.h>,
non-e500 nofpu no longer needs an fenv_libc.h file.
The other macros in fenvinline.h are left conditional on
__NO_MATH_INLINES, although since the only case where this should make
a difference is one involving undefined behavior (if the argument to
the function is not a valid exception macro).
The out-of-line definition for fegetround uses __fegetround (the
inline function removed by this patch). So this continues to work,
the fenvinline.h header is made to define __fegetround, and then to
define fegetround to call __fegetround.
Tested for powerpc32 (hard float) that installed stripped shared
libraries are unchanged by this patch; also tested that powerpc-nofpu
build still works. (This patch does not itself fix any bugs; it
simply cleans things up in preparation for separate bug fixes.)
* sysdeps/powerpc/bits/fenvinline.h (fegetround): Rename macro to
__fegetround and redefine to call __fegetround. Remove condition
on [!__NO_MATH_INLINES].
* sysdeps/powerpc/fpu/fenv_libc.h (__fegetround): Remove inline
function.
* sysdeps/powerpc/nofpu/fenv_libc.h: Remove file.
* sysdeps/powerpc/powerpc32/e500/nofpu/fenv_libc.h (__fegetround):
Remove macro.
* sysdeps/ieee754/ldbl-128ibm/s_llrintl.c: Include <fenv.h>
instead of <fenv_libc.h>.
(__llrintl): Call fegetround instead of __fegetround.
* sysdeps/ieee754/ldbl-128ibm/s_llroundl.c: Include <fenv.h>
instead of <fenv_libc.h>.
* sysdeps/ieee754/ldbl-128ibm/s_lrintl.c: Likewise.
(__lrintl): Call fegetround instead of __fegetround.
* sysdeps/ieee754/ldbl-128ibm/s_lroundl.c: Include <fenv.h>
instead of <fenv_libc.h>.
* sysdeps/ieee754/ldbl-128ibm/s_rintl.c: Likewise.
(__rintl): Call fegetround instead of __fegetround.
2014-12-31 19:16:34 +00:00
|
|
|
#include <fenv.h>
|
2018-03-07 16:45:35 +00:00
|
|
|
#include <math_private.h>
|
2006-01-28 00:15:15 +00:00
|
|
|
#include <math_ldbl_opt.h>
|
2006-09-17 07:26:24 +00:00
|
|
|
#include <float.h>
|
|
|
|
#include <ieee754.h>
|
2006-01-28 00:15:15 +00:00
|
|
|
|
2006-09-17 07:26:24 +00:00
|
|
|
long
|
|
|
|
__lroundl (long double x)
|
2006-01-28 00:15:15 +00:00
|
|
|
{
|
2006-09-17 07:26:24 +00:00
|
|
|
double xh, xl;
|
|
|
|
long res, hi, lo;
|
|
|
|
|
|
|
|
ldbl_unpack (x, &xh, &xl);
|
|
|
|
|
|
|
|
/* Limit the range of values handled by the conversion to long.
|
|
|
|
We do this because we aren't sure whether that conversion properly
|
|
|
|
raises FE_INVALID. */
|
|
|
|
if (
|
|
|
|
#if __LONG_MAX__ == 2147483647
|
|
|
|
__builtin_expect
|
|
|
|
((__builtin_fabs (xh) <= (double) __LONG_MAX__ + 2), 1)
|
|
|
|
#else
|
|
|
|
__builtin_expect
|
|
|
|
((__builtin_fabs (xh) <= -(double) (-__LONG_MAX__ - 1)), 1)
|
|
|
|
#endif
|
|
|
|
#if !defined (FE_INVALID)
|
|
|
|
|| 1
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
#if __LONG_MAX__ == 2147483647
|
|
|
|
long long llhi = (long long) xh;
|
|
|
|
if (llhi != (long) llhi)
|
|
|
|
hi = llhi < 0 ? -__LONG_MAX__ - 1 : __LONG_MAX__;
|
|
|
|
else
|
|
|
|
hi = llhi;
|
|
|
|
xh -= hi;
|
|
|
|
#else
|
2014-02-10 13:45:42 +00:00
|
|
|
if (__glibc_unlikely ((xh == -(double) (-__LONG_MAX__ - 1))))
|
2006-09-17 07:26:24 +00:00
|
|
|
{
|
|
|
|
/* When XH is 9223372036854775808.0, converting to long long will
|
|
|
|
overflow, resulting in an invalid operation. However, XL might
|
|
|
|
be negative and of sufficient magnitude that the overall long
|
|
|
|
double is in fact in range. Avoid raising an exception. In any
|
|
|
|
case we need to convert this value specially, because
|
|
|
|
the converted value is not exactly represented as a double
|
|
|
|
thus subtracting HI from XH suffers rounding error. */
|
|
|
|
hi = __LONG_MAX__;
|
|
|
|
xh = 1.0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
hi = (long) xh;
|
|
|
|
xh -= hi;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
ldbl_canonicalize (&xh, &xl);
|
|
|
|
|
|
|
|
lo = (long) xh;
|
|
|
|
|
|
|
|
/* Peg at max/min values, assuming that the above conversions do so.
|
|
|
|
Strictly speaking, we can return anything for values that overflow,
|
|
|
|
but this is more useful. */
|
2018-01-10 00:02:35 +00:00
|
|
|
res = (long int) ((unsigned long int) hi + (unsigned long int) lo);
|
2006-09-17 07:26:24 +00:00
|
|
|
|
|
|
|
/* This is just sign(hi) == sign(lo) && sign(res) != sign(hi). */
|
2014-02-10 13:45:42 +00:00
|
|
|
if (__glibc_unlikely (((~(hi ^ lo) & (res ^ hi)) < 0)))
|
2006-09-17 07:26:24 +00:00
|
|
|
goto overflow;
|
|
|
|
|
|
|
|
xh -= lo;
|
|
|
|
ldbl_canonicalize (&xh, &xl);
|
|
|
|
|
|
|
|
hi = res;
|
|
|
|
if (xh > 0.5)
|
|
|
|
{
|
2018-01-10 00:02:35 +00:00
|
|
|
res += 1UL;
|
2006-09-17 07:26:24 +00:00
|
|
|
}
|
|
|
|
else if (xh == 0.5)
|
|
|
|
{
|
|
|
|
if (xl > 0.0 || (xl == 0.0 && res >= 0))
|
2018-01-10 00:02:35 +00:00
|
|
|
res += 1UL;
|
2006-09-17 07:26:24 +00:00
|
|
|
}
|
|
|
|
else if (-xh > 0.5)
|
|
|
|
{
|
2018-01-10 00:02:35 +00:00
|
|
|
res -= 1UL;
|
2006-09-17 07:26:24 +00:00
|
|
|
}
|
|
|
|
else if (-xh == 0.5)
|
|
|
|
{
|
|
|
|
if (xl < 0.0 || (xl == 0.0 && res <= 0))
|
2018-01-10 00:02:35 +00:00
|
|
|
res -= 1UL;
|
2006-09-17 07:26:24 +00:00
|
|
|
}
|
|
|
|
|
2014-02-10 13:45:42 +00:00
|
|
|
if (__glibc_unlikely (((~(hi ^ (res - hi)) & (res ^ hi)) < 0)))
|
2006-09-17 07:26:24 +00:00
|
|
|
goto overflow;
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (xh > 0.0)
|
|
|
|
hi = __LONG_MAX__;
|
|
|
|
else if (xh < 0.0)
|
|
|
|
hi = -__LONG_MAX__ - 1;
|
|
|
|
else
|
|
|
|
/* Nan */
|
|
|
|
hi = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
overflow:
|
|
|
|
#ifdef FE_INVALID
|
|
|
|
feraiseexcept (FE_INVALID);
|
|
|
|
#endif
|
|
|
|
return hi;
|
2006-01-28 00:15:15 +00:00
|
|
|
}
|
2006-09-17 07:26:24 +00:00
|
|
|
|
2006-01-28 00:15:15 +00:00
|
|
|
long_double_symbol (libm, __lroundl, lroundl);
|