glibc/sysdeps/ieee754/ldbl-128ibm/s_truncl.c
Roland McGrath 5c68d40169 [BZ #2423]
2006-03-07  Jakub Jelinek  <jakub@redhat.com>
	[BZ #2423]
	* math/libm-test.inc [TEST_LDOUBLE] (ceil_test, floor_test, rint_test,
	round_test, trunc_test): Only run some of the new tests if
	LDBL_MANT_DIG > 100.

2006-03-03  Steven Munroe  <sjmunroe@us.ibm.com>
	    Alan Modra  <amodra@bigpond.net.au>

	* sysdeps/powerpc/fpu/fenv_libc.h (__fegetround, __fesetround):
	Define inline implementations.
	* sysdeps/powerpc/fpu/fegetround.c: Use __fegetround.
	* sysdeps/powerpc/fpu/fesetround.c: Use __fesetround.

	* sysdeps/powerpc/fpu/math_ldbl.h: New file.

	[BZ #2423]
	* math/libm-test.inc [TEST_LDOUBLE] (ceil_test, floor_test, rint_test,
	round_test, trunc_test): Add new tests.
	* sysdeps/ieee754/ldbl-128ibm/math_ldbl.h
	(EXTRACT_IBM_EXTENDED_MANTISSA, INSERT_IBM_EXTENDED_MANTISSA):
	Removed, replaced with ...
	(ldbl_extract_mantissa, ldbl_insert_mantissa, ldbl_pack, ldbl_unpack,
	ldbl_canonicalise, ldbl_nearbyint): New functions.
	* sysdeps/ieee754/ldbl-128ibm/e_fmodl.c (__ieee754_fmodl): Replace
	EXTRACT_IBM_EXTENDED_MANTISSA and INSERT_IBM_EXTENDED_MANTISSA
	with ldbl_extract_mantissa and ldbl_insert_mantissa.
	* sysdeps/ieee754/ldbl-128ibm/e_rem_pio2l.c (__ieee754_rem_pio2l):
	Replace EXTRACT_IBM_EXTENDED_MANTISSA with ldbl_extract_mantissa.
	(ldbl_extract_mantissa, ldbl_insert_mantissa): New inline functions.
	* sysdeps/ieee754/ldbl-128ibm/s_ceill.c (__ceill): Handle rounding
	that spans doubles in IBM long double format.
	* sysdeps/ieee754/ldbl-128ibm/s_floorl.c: Likewise.
	* sysdeps/ieee754/ldbl-128ibm/s_rintl.c: Likewise.
	* sysdeps/ieee754/ldbl-128ibm/s_roundl.c: Likewise.
	* sysdeps/ieee754/ldbl-128ibm/s_truncl.c: Likewise.
	* sysdeps/powerpc/powerpc64/fpu/s_rintl.S: File removed.
2006-03-16 11:47:24 +00:00

103 lines
2.9 KiB
C

/* Truncate (toward zero) long double floating-point values.
IBM extended format long double version.
Copyright (C) 2006 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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* This has been coded in assembler because GCC makes such a mess of it
when it's coded in C. */
#include <math.h>
#include <fenv_libc.h>
#include <math_ldbl_opt.h>
#include <float.h>
#include <ieee754.h>
#ifdef __STDC__
long double
__truncl (long double x)
#else
long double
__truncl (x)
long double x;
#endif
{
double xh, xl, hi, lo;
ldbl_unpack (x, &xh, &xl);
/* Return Inf, Nan, +/-0 unchanged. */
if (__builtin_expect (xh != 0.0
&& __builtin_isless (__builtin_fabs (xh),
__builtin_inf ()), 1))
{
double orig_xh;
int save_round = fegetround ();
/* Long double arithmetic, including the canonicalisation below,
only works in round-to-nearest mode. */
fesetround (FE_TONEAREST);
/* Convert the high double to integer. */
orig_xh = xh;
hi = ldbl_nearbyint (xh);
/* Subtract integral high part from the value. */
xh -= hi;
ldbl_canonicalize (&xh, &xl);
/* Now convert the low double, adjusted for any remainder from the
high double. */
lo = ldbl_nearbyint (xh);
/* Adjust the result when the remainder is non-zero. nearbyint
rounds values to the nearest integer, and values halfway
between integers to the nearest even integer. floorl must
round towards -Inf. */
xh -= lo;
ldbl_canonicalize (&xh, &xl);
if (orig_xh < 0.0)
{
if (xh > 0.0 || (xh == 0.0 && xl > 0.0))
lo += 1.0;
}
else
{
if (xh < 0.0 || (xh == 0.0 && xl < 0.0))
lo -= 1.0;
}
/* Ensure the final value is canonical. In certain cases,
rounding causes hi,lo calculated so far to be non-canonical. */
xh = hi;
xl = lo;
ldbl_canonicalize (&xh, &xl);
/* Ensure we return -0 rather than +0 when appropriate. */
if (orig_xh < 0.0)
xh = -__builtin_fabs (xh);
fesetround (save_round);
}
return ldbl_pack (xh, xl);
}
long_double_symbol (libm, __truncl, truncl);