mirror of
https://sourceware.org/git/glibc.git
synced 2024-12-23 11:20:07 +00:00
72d839a42f
The dbl-64 implementation of __ieee754_pow returns a NaN for pow (qNaN, 0) when it should return 1. Normally this is covered up by the wrappers ending up calling __kernel_standard which fixes up the result for this case, but for -lieee the wrappers are bypassed and the bad result gets through as a return value. Now, the wrappers fixing this are dealing with variant error handling that wants a result of NaN for pow (qNaN, 0), and only ever call __kernel_standard for this case if NaN resulted from __ieee754_pow. This leads to a question of whether the dbl-64 code might be deliberately returning NaN in order to use those code paths. However, I can find no sign that this is deliberate. If it were deliberate one would expect other implementations to do the same, and would expect the return of NaN to be very old, but it appears it came in by accident when the present e_pow.c implementation replaced an fdlibm implementation in 2001. So it appears to be unintended that this path through the pow wrapper could be used at all. So this patch fixes the implementation to return 1 in this case as expected. This is consistent with all the other implementations. The relevant path through the wrappers is now unreachable, so is removed (which is the main motivation of this patch: to avoid that path becoming accidentally reachable when implementing TS 18661-1 semantics that pow (sNaN, 0) should return qNaN with "invalid" raised). Another path that would require __ieee754_pow (0, 0) to return 0 is also unreachable (as all implementations return 1, in accordance with C99 semantics), so is removed as well. Note: we don't have anything set up to test -lieee, which in any case is obsolescent (at some point we should remove the ability for new programs to access _LIB_VERSION or define matherr and have it called by glibc). So testing will be implicit through sNaN tests added when making sNaN inputs work correctly for pow functions. Tested for x86_64 and x86. [BZ #20919] * sysdeps/ieee754/dbl-64/e_pow.c (__ieee754_pow): Do not return NaN first argument when raised to power 0. * math/w_pow.c (__pow): Do not check for NaN or zero results from raising to power zero. * math/w_powf.c (__powf): Likewise. * math/w_powl.c (__powl): Likewise. * sysdeps/ieee754/k_standard.c (__kernel_standard): Do not handle pow (0, 0) or pow (NaN, 0).
65 lines
1.8 KiB
C
65 lines
1.8 KiB
C
/* Copyright (C) 2011-2016 Free Software Foundation, Inc.
|
|
This file is part of the GNU C Library.
|
|
Contributed by Ulrich Drepper <drepper@gmail.com>, 2011.
|
|
|
|
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/>. */
|
|
|
|
#include <math.h>
|
|
#include <math_private.h>
|
|
|
|
|
|
/* wrapper pow */
|
|
double
|
|
__pow (double x, double y)
|
|
{
|
|
double z = __ieee754_pow (x, y);
|
|
if (__glibc_unlikely (!isfinite (z)))
|
|
{
|
|
if (_LIB_VERSION != _IEEE_)
|
|
{
|
|
if (isfinite (x) && isfinite (y))
|
|
{
|
|
if (isnan (z))
|
|
/* pow neg**non-int */
|
|
return __kernel_standard (x, y, 24);
|
|
else if (x == 0.0 && y < 0.0)
|
|
{
|
|
if (signbit (x) && signbit (z))
|
|
/* pow(-0.0,negative) */
|
|
return __kernel_standard (x, y, 23);
|
|
else
|
|
/* pow(+0.0,negative) */
|
|
return __kernel_standard (x, y, 43);
|
|
}
|
|
else
|
|
/* pow overflow */
|
|
return __kernel_standard (x, y, 21);
|
|
}
|
|
}
|
|
}
|
|
else if (__builtin_expect (z == 0.0, 0)
|
|
&& isfinite (x) && x != 0 && isfinite (y)
|
|
&& _LIB_VERSION != _IEEE_)
|
|
/* pow underflow */
|
|
return __kernel_standard (x, y, 22);
|
|
|
|
return z;
|
|
}
|
|
weak_alias (__pow, pow)
|
|
#ifdef NO_LONG_DOUBLE
|
|
strong_alias (__pow, __powl)
|
|
weak_alias (__pow, powl)
|
|
#endif
|