Use the expression fabs(x+0.0)+fabs(y+0.0) instad of a+b (where a is

|x| or |y| and b is |y| or |x|) when mixing NaN arg(s).

hypot*() had its own foot shooting for mixing NaNs -- it swaps the
args so that |x| in bits is largest, but does this before quieting
signaling NaNs, so on amd64 (where the result of adding NaNs depends
on the order) it gets inconsistent results if setting the quiet bit
makes a difference, just like a similar ia64 and i387 hardware comparison.
The usual fix (see e_powf.c 1.13 for more details) of mixing using
(a+0.0)+-(b+0.0) doesn't work on amd64 if the args are swapped (since
the rder makes a difference with SSE). Fortunately, the original args
are unchanged and don't need to be swapped when we let the hardware
decide the mixing after quieting them, but we need to take their
absolute value.

hypotf() doesn't seem to have any real bugs masked by this non-bug.
On amd64, its maximum error in 2^32 trials on amd64 is now 0.8422 ulps,
and on i386 the maximum error is unchanged and about the same, except
with certain CFLAGS it magically drops to 0.5 (perfect rounding).

Convert to __FBSDID().
This commit is contained in:
Bruce Evans 2008-02-14 13:44:03 +00:00
parent 8e97417475
commit 3365b45e5e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=176277
2 changed files with 8 additions and 8 deletions

View File

@ -11,9 +11,8 @@
* ====================================================
*/
#ifndef lint
static char rcsid[] = "$FreeBSD$";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/* __ieee754_hypot(x,y)
*
@ -68,7 +67,8 @@ __ieee754_hypot(double x, double y)
if(ha > 0x5f300000) { /* a>2**500 */
if(ha >= 0x7ff00000) { /* Inf or NaN */
u_int32_t low;
w = a+b; /* for sNaN */
/* Use original arg order iff result is NaN; quieten sNaNs. */
w = fabs(x+0.0)+fabs(y+0.0);
GET_LOW_WORD(low,a);
if(((ha&0xfffff)|low)==0) w = a;
GET_LOW_WORD(low,b);

View File

@ -13,9 +13,8 @@
* ====================================================
*/
#ifndef lint
static char rcsid[] = "$FreeBSD$";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include "math.h"
#include "math_private.h"
@ -37,7 +36,8 @@ __ieee754_hypotf(float x, float y)
k=0;
if(ha > 0x58800000) { /* a>2**50 */
if(ha >= 0x7f800000) { /* Inf or NaN */
w = a+b; /* for sNaN */
/* Use original arg order iff result is NaN; quieten sNaNs. */
w = fabsf(x+0.0F)+fabsf(y+0.0F);
if(ha == 0x7f800000) w = a;
if(hb == 0x7f800000) w = b;
return w;