mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-24 03:31:07 +00:00
b93c2205ec
Continuing the fixes for C90 libm functions calling C99 fe* functions, this patch fixes the case of fegetround by making it a weak alias of __fegetround and making the affected code call __fegetround. Tested for x86_64 (testsuite, and that disassembly of installed shared libraries is unchanged by the patch). Also tested for ARM (soft-float) that fegetround failures disappear from the linknamespace test failures (feholdexcept, fesetenv, fesetround and feupdateenv remain to be addressed before bug 17748 is fully fixed, although this patch may suffice to fix the failures in some cases, when the libc_fe* functions are implemented but there is no architecture-specific sqrt implementation in use so there were failures from fegetround used by sqrt but no other such failures). [BZ #17748] * include/fenv.h (__fegetround): Declare. Use libm_hidden_proto. * math/fegetround.c (fegetround): Rename to __fegetround and define as weak alias of __fegetround. Use libm_hidden_weak. * sysdeps/aarch64/fpu/fegetround.c (fegetround): Likewise. * sysdeps/alpha/fpu/fegetround.c (fegetround): Likewise. * sysdeps/arm/fegetround.c (fegetround): Likewise. * sysdeps/hppa/fpu/fegetround.c (fegetround): Likewise. * sysdeps/i386/fpu/fegetround.c (fegetround): Likewise. * sysdeps/ia64/fpu/fegetround.c (fegetround): Likewise. * sysdeps/m68k/fpu/fegetround.c (fegetround): Likewise. * sysdeps/mips/fpu/fegetround.c (fegetround): Likewise. * sysdeps/powerpc/fpu/fegetround.c (fegetround): Likewise. Undefine after rather than before function definition; use parentheses around function name in definition. (__fegetround): Also undefine macro after function definition. * sysdeps/powerpc/nofpu/fegetround.c (fegetround): Rename to __fegetround and define as weak alias of __fegetround. Use libm_hidden_weak. Do not undefine as macro. * sysdeps/powerpc/powerpc32/e500/nofpu/fegetround.c (fegetround): Likewise. * sysdeps/s390/fpu/fegetround.c (fegetround): Rename to __fegetround and define as weak alias of __fegetround. Use libm_hidden_weak. * sysdeps/sh/sh4/fpu/fegetround.c (fegetround): Likewise. * sysdeps/sparc/fpu/fegetround.c (fegetround): Likewise. * sysdeps/tile/math_private.h (__fegetround): New inline function. * sysdeps/x86_64/fpu/fegetround.c (fegetround): Rename to __fegetround and define as weak alias of __fegetround. Use libm_hidden_weak. * sysdeps/ieee754/dbl-64/e_sqrt.c (__ieee754_sqrt): Use __fegetround instead of fegetround.
141 lines
4.9 KiB
C
141 lines
4.9 KiB
C
/*
|
|
* IBM Accurate Mathematical Library
|
|
* written by International Business Machines Corp.
|
|
* Copyright (C) 2001-2015 Free Software Foundation, Inc.
|
|
*
|
|
* This program 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.
|
|
*
|
|
* This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
/*********************************************************************/
|
|
/* MODULE_NAME: uroot.c */
|
|
/* */
|
|
/* FUNCTION: usqrt */
|
|
/* */
|
|
/* FILES NEEDED: dla.h endian.h mydefs.h uroot.h */
|
|
/* uroot.tbl */
|
|
/* */
|
|
/* An ultimate sqrt routine. Given an IEEE double machine number x */
|
|
/* it computes the correctly rounded (to nearest) value of square */
|
|
/* root of x. */
|
|
/* Assumption: Machine arithmetic operations are performed in */
|
|
/* round to nearest mode of IEEE 754 standard. */
|
|
/* */
|
|
/*********************************************************************/
|
|
|
|
#include "endian.h"
|
|
#include "mydefs.h"
|
|
#include <dla.h>
|
|
#include "MathLib.h"
|
|
#include "root.tbl"
|
|
#include <math_private.h>
|
|
|
|
/*********************************************************************/
|
|
/* An ultimate sqrt routine. Given an IEEE double machine number x */
|
|
/* it computes the correctly rounded (to nearest) value of square */
|
|
/* root of x. */
|
|
/*********************************************************************/
|
|
double
|
|
__ieee754_sqrt (double x)
|
|
{
|
|
#include "uroot.h"
|
|
static const double
|
|
rt0 = 9.99999999859990725855365213134618E-01,
|
|
rt1 = 4.99999999495955425917856814202739E-01,
|
|
rt2 = 3.75017500867345182581453026130850E-01,
|
|
rt3 = 3.12523626554518656309172508769531E-01;
|
|
static const double big = 134217728.0;
|
|
double y, t, del, res, res1, hy, z, zz, p, hx, tx, ty, s;
|
|
mynumber a, c = { { 0, 0 } };
|
|
int4 k;
|
|
|
|
a.x = x;
|
|
k = a.i[HIGH_HALF];
|
|
a.i[HIGH_HALF] = (k & 0x001fffff) | 0x3fe00000;
|
|
t = inroot[(k & 0x001fffff) >> 14];
|
|
s = a.x;
|
|
/*----------------- 2^-1022 <= | x |< 2^1024 -----------------*/
|
|
if (k > 0x000fffff && k < 0x7ff00000)
|
|
{
|
|
int rm = __fegetround ();
|
|
fenv_t env;
|
|
libc_feholdexcept_setround (&env, FE_TONEAREST);
|
|
double ret;
|
|
y = 1.0 - t * (t * s);
|
|
t = t * (rt0 + y * (rt1 + y * (rt2 + y * rt3)));
|
|
c.i[HIGH_HALF] = 0x20000000 + ((k & 0x7fe00000) >> 1);
|
|
y = t * s;
|
|
hy = (y + big) - big;
|
|
del = 0.5 * t * ((s - hy * hy) - (y - hy) * (y + hy));
|
|
res = y + del;
|
|
if (res == (res + 1.002 * ((y - res) + del)))
|
|
ret = res * c.x;
|
|
else
|
|
{
|
|
res1 = res + 1.5 * ((y - res) + del);
|
|
EMULV (res, res1, z, zz, p, hx, tx, hy, ty); /* (z+zz)=res*res1 */
|
|
res = ((((z - s) + zz) < 0) ? max (res, res1) :
|
|
min (res, res1));
|
|
ret = res * c.x;
|
|
}
|
|
math_force_eval (ret);
|
|
libc_fesetenv (&env);
|
|
double dret = x / ret;
|
|
if (dret != ret)
|
|
{
|
|
double force_inexact = 1.0 / 3.0;
|
|
math_force_eval (force_inexact);
|
|
/* The square root is inexact, ret is the round-to-nearest
|
|
value which may need adjusting for other rounding
|
|
modes. */
|
|
switch (rm)
|
|
{
|
|
#ifdef FE_UPWARD
|
|
case FE_UPWARD:
|
|
if (dret > ret)
|
|
ret = (res + 0x1p-1022) * c.x;
|
|
break;
|
|
#endif
|
|
|
|
#ifdef FE_DOWNWARD
|
|
case FE_DOWNWARD:
|
|
#endif
|
|
#ifdef FE_TOWARDZERO
|
|
case FE_TOWARDZERO:
|
|
#endif
|
|
#if defined FE_DOWNWARD || defined FE_TOWARDZERO
|
|
if (dret < ret)
|
|
ret = (res - 0x1p-1022) * c.x;
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
/* Otherwise (x / ret == ret), either the square root was exact or
|
|
the division was inexact. */
|
|
return ret;
|
|
}
|
|
else
|
|
{
|
|
if ((k & 0x7ff00000) == 0x7ff00000)
|
|
return x * x + x; /* sqrt(NaN)=NaN, sqrt(+inf)=+inf, sqrt(-inf)=sNaN */
|
|
if (x == 0)
|
|
return x; /* sqrt(+0)=+0, sqrt(-0)=-0 */
|
|
if (k < 0)
|
|
return (x - x) / (x - x); /* sqrt(-ve)=sNaN */
|
|
return tm256.x * __ieee754_sqrt (x * t512.x);
|
|
}
|
|
}
|
|
strong_alias (__ieee754_sqrt, __sqrt_finite)
|