[PATCH v2 20/25] math: Use atanf from CORE-MATH

DJ Delorie dj@redhat.com
Mon Dec 9 18:09:25 GMT 2024


Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
> The CORE-MATH implementation is correctly rounded (for any rounding mode)
> and shows slight better performance to the generic atanf.

One question about the tail and of sysdeps/ieee754/flt-32/s_atanf.c wrt copysign

ulps change includes increase in cacos() ulps on some platforms?

LGTM if those are addressed
Reviewed-by: DJ Delorie <dj@redhat.com>

> diff --git a/SHARED-FILES b/SHARED-FILES
> index 18b3244e44..b9627afdfe 100644
> --- a/SHARED-FILES
> +++ b/SHARED-FILES
> @@ -310,3 +310,7 @@ sysdeps/ieee754/flt-32/s_asinhf.c:
>    (src/binary32/asinh/asinhf.c in CORE-MATH)
>    - The code was adapted to use glibc code style and internal
>      functions to handle errno, overflow, and underflow.
> +sysdeps/ieee754/flt-32/s_atanf.c:
> +  (src/binary32/atan/atanf.c in CORE-MATH)
> +  - The code was adapted to use glibc code style and internal
> +    functions to handle errno, overflow, and underflow.

Ok.

> diff --git a/sysdeps/aarch64/libm-test-ulps b/sysdeps/aarch64/libm-test-ulps
>  
>  Function: Real part of "cacos_towardzero":
>  double: 3
> -float: 2
> +float: 3
>  ldouble: 3
>  
>  Function: Imaginary part of "cacos_towardzero":
> @@ -263,7 +259,7 @@ ldouble: 5
>  
>  Function: Imaginary part of "cacosh_towardzero":
>  double: 3
> -float: 2
> +float: 3
>  ldouble: 3

I don't see how these are related, but... ok?

> diff --git a/sysdeps/alpha/fpu/libm-test-ulps b/sysdeps/alpha/fpu/libm-test-ulps
> diff --git a/sysdeps/arc/fpu/libm-test-ulps b/sysdeps/arc/fpu/libm-test-ulps
> diff --git a/sysdeps/arc/nofpu/libm-test-ulps b/sysdeps/arc/nofpu/libm-test-ulps
> diff --git a/sysdeps/arm/libm-test-ulps b/sysdeps/arm/libm-test-ulps
> diff --git a/sysdeps/csky/fpu/libm-test-ulps b/sysdeps/csky/fpu/libm-test-ulps
> diff --git a/sysdeps/csky/nofpu/libm-test-ulps b/sysdeps/csky/nofpu/libm-test-ulps
> diff --git a/sysdeps/hppa/fpu/libm-test-ulps b/sysdeps/hppa/fpu/libm-test-ulps
> diff --git a/sysdeps/i386/fpu/libm-test-ulps b/sysdeps/i386/fpu/libm-test-ulps

Ok.

> diff --git a/sysdeps/i386/fpu/s_atanf.S b/sysdeps/i386/fpu/s_atanf.S
> deleted file mode 100644

Ok.

> diff --git a/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps b/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps

Ok.

> diff --git a/sysdeps/ieee754/flt-32/s_atanf.c b/sysdeps/ieee754/flt-32/s_atanf.c
> index 3dbf5c5bb7..7a5cf4d5b1 100644
> --- a/sysdeps/ieee754/flt-32/s_atanf.c
> +++ b/sysdeps/ieee754/flt-32/s_atanf.c
> @@ -1,102 +1,106 @@
> -/* s_atanf.c -- float version of s_atan.c.
> - */
> +/* Correctly-rounded arc-tangent of binary32 value.
>  
> -/*
> - * ====================================================
> - * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
> - *
> - * Developed at SunPro, a Sun Microsystems, Inc. business.
> - * Permission to use, copy, modify, and distribute this
> - * software is freely granted, provided that this notice
> - * is preserved.
> - * ====================================================
> - */
> +Copyright (c) 2022-2024 Alexei Sibidanov.
>  
> -#if defined(LIBM_SCCS) && !defined(lint)
> -static char rcsid[] = "$NetBSD: s_atanf.c,v 1.4 1995/05/10 20:46:47 jtc Exp $";
> -#endif
> +The original version of this file was copied from the CORE-MATH
> +project (file src/binary32/atan/atanf.c, revision 01a29dc).
>  
> -#include <float.h>
> -#include <math.h>
> -#include <math_private.h>
> -#include <math-underflow.h>
> -#include <libm-alias-float.h>
> +Permission is hereby granted, free of charge, to any person obtaining a copy
> +of this software and associated documentation files (the "Software"), to deal
> +in the Software without restriction, including without limitation the rights
> +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> +copies of the Software, and to permit persons to whom the Software is
> +furnished to do so, subject to the following conditions:
>  
> -static const float atanhi[] = {
> -  4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
> -  7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
> -  9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
> -  1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
> -};
> +The above copyright notice and this permission notice shall be included in all
> +copies or substantial portions of the Software.
>  
> -static const float atanlo[] = {
> -  5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
> -  3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
> -  3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
> -  7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
> -};
> +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
> +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
> +SOFTWARE.
> +*/

Ok.

> -static const float aT[] = {
> -  3.3333334327e-01, /* 0x3eaaaaaa */
> - -2.0000000298e-01, /* 0xbe4ccccd */
> -  1.4285714924e-01, /* 0x3e124925 */
> - -1.1111110449e-01, /* 0xbde38e38 */
> -  9.0908870101e-02, /* 0x3dba2e6e */
> - -7.6918758452e-02, /* 0xbd9d8795 */
> -  6.6610731184e-02, /* 0x3d886b35 */
> - -5.8335702866e-02, /* 0xbd6ef16b */
> -  4.9768779427e-02, /* 0x3d4bda59 */
> - -3.6531571299e-02, /* 0xbd15a221 */
> -  1.6285819933e-02, /* 0x3c8569d7 */
> -};
> -
> -static const float
> -one   = 1.0,
> -huge   = 1.0e30;

ok.

> +#include <math.h>
> +#include <stdint.h>
> +#include <libm-alias-float.h>
> +#include "math_config.h"
>  
> -float __atanf(float x)
> +float
> +__atanf (float x)
>  {

Ok.

> -	float w,s1,s2,z;
> -	int32_t ix,hx,id;
> -
> -	GET_FLOAT_WORD(hx,x);
> -	ix = hx&0x7fffffff;
> -	if(ix>=0x4c000000) {	/* if |x| >= 2^25 */
> -	    if(ix>0x7f800000)
> -		return x+x;		/* NaN */
> -	    if(hx>0) return  atanhi[3]+atanlo[3];
> -	    else     return -atanhi[3]-atanlo[3];
> -	} if (ix < 0x3ee00000) {	/* |x| < 0.4375 */
> -	    if (ix < 0x31000000) {	/* |x| < 2^-29 */
> -		math_check_force_underflow (x);
> -		if(huge+x>one) return x;	/* raise inexact */
> -	    }
> -	    id = -1;
> -	} else {
> -	x = fabsf(x);
> -	if (ix < 0x3f980000) {		/* |x| < 1.1875 */
> -	    if (ix < 0x3f300000) {	/* 7/16 <=|x|<11/16 */
> -		id = 0; x = ((float)2.0*x-one)/((float)2.0+x);
> -	    } else {			/* 11/16<=|x|< 19/16 */
> -		id = 1; x  = (x-one)/(x+one);
> -	    }
> -	} else {
> -	    if (ix < 0x401c0000) {	/* |x| < 2.4375 */
> -		id = 2; x  = (x-(float)1.5)/(one+(float)1.5*x);
> -	    } else {			/* 2.4375 <= |x| < 2^66 */
> -		id = 3; x  = -(float)1.0/x;
> -	    }
> -	}}
> -    /* end of argument reduction */
> -	z = x*x;
> -	w = z*z;
> -    /* break sum from i=0 to 10 aT[i]z**(i+1) into odd and even poly */
> -	s1 = z*(aT[0]+w*(aT[2]+w*(aT[4]+w*(aT[6]+w*(aT[8]+w*aT[10])))));
> -	s2 = w*(aT[1]+w*(aT[3]+w*(aT[5]+w*(aT[7]+w*aT[9]))));
> -	if (id<0) return x - x*(s1+s2);
> -	else {
> -	    z = atanhi[id] - ((x*(s1+s2) - atanlo[id]) - x);
> -	    return (hx<0)? -z:z;

Ok.

> +  const double pi2 = 0x1.921fb54442d18p+0;
> +  uint32_t t = asuint (x);
> +  int e = (t >> 23) & 0xff;
> +  bool gt = e >= 127;
> +  uint32_t ta = t & 0x7fffffff;
> +  if (__glibc_unlikely (ta >= 0x4c700518u)) /* |x| > 0x1.e00a3p+25 */
> +    {
> +      if (ta > 0x7f800000u)
> +	return x + x; /* nan */
> +      return copysign (pi2, (double) x);
> +    }
> +  if (__glibc_unlikely (e < 127 - 13))
> +    {
> +      if (__glibc_unlikely (e < 127 - 25))
> +	{
> +	  if (!(t << 1))
> +	    return x;
> +	  return fmaf (-x, fabsf (x), x);
>  	}
> +      return fmaf (-0x1.5555555555555p-2f * x, x * x, x);
> +    }
> +  /* now |x| >= 0x1p-13 */
> +  double z = x;
> +  if (gt)
> +    z = 1 / z; /* gt is non-zero for |x| >= 1 */
> +  double z2 = z * z;
> +  double z4 = z2 * z2;
> +  double z8 = z4 * z4;
> +  /* polynomials generated using rminimax
> +     (https://gitlab.inria.fr/sfilip/rminimax) with the following command:
> +     ./ratapprox --function="atan(x)" --dom=[0.000122070,1]
> +     --num=[x,x^3,x^5,x^7,x^9,x^11,x^13] --den=[1,x^2,x^4,x^6,x^8,x^10,x^12]
> +     --output=atanf.sollya --log (see output atanf.sollya) The coefficient
> +     cd[0] was slightly reduced from the original value 0x1.51eccde075d67p-2 to
> +     avoid an exceptional case for |x| = 0x1.1ad646p-4 and rounding to nearest.
> +  */
> +  static const double cn[] =
> +    {
> +      0x1.51eccde075d67p-2, 0x1.a76bb5637f2f2p-1, 0x1.81e0eed20de88p-1,
> +      0x1.376c8ca67d11dp-2, 0x1.aec7b69202ac6p-5, 0x1.9561899acc73ep-9,
> +      0x1.bf9fa5b67e6p-16
> +    };
> +  static const double cd[] =
> +    {
> +      0x1.51eccde075d66p-2, 0x1.dfbdd7b392d28p-1, 0x1p+0,
> +      0x1.fd22bf0e89b54p-2, 0x1.d91ff8b576282p-4, 0x1.653ea99fc9bbp-7,
> +      0x1.1e7fcc202340ap-12
> +    };

Ok.

> +  double cn0 = cn[0] + z2 * cn[1];
> +  double cn2 = cn[2] + z2 * cn[3];
> +  double cn4 = cn[4] + z2 * cn[5];
> +  double cn6 = cn[6];
> +  cn0 += z4 * cn2;
> +  cn4 += z4 * cn6;
> +  cn0 += z8 * cn4;
> +  cn0 *= z;
> +  double cd0 = cd[0] + z2 * cd[1];
> +  double cd2 = cd[2] + z2 * cd[3];
> +  double cd4 = cd[4] + z2 * cd[5];
> +  double cd6 = cd[6];
> +  cd0 += z4 * cd2;
> +  cd4 += z4 * cd6;
> +  cd0 += z8 * cd4;
> +  double r = cn0 / cd0;
> +  if (!gt)
> +    return r; /* for |x| < 1, (float) r is correctly rounded */

Ok.

> +  /* now |x| >= 1 */
> +  r = copysign (0x1.0fdaa22168c23p-7, z) - r + copysign (0x1.9p0, z);

This seems odd; there's no reason to have two copysign's - they could be
combines into "copysign(...) - r".  Unless there's rounding issues, in
which case, a comment and parens are warranted to force operation order
despite optimizations.

> +  return r;
>  }
>  libm_alias_float (__atan, atan)

Ok.

> diff --git a/sysdeps/loongarch/lp64/libm-test-ulps b/sysdeps/loongarch/lp64/libm-test-ulps
> diff --git a/sysdeps/microblaze/libm-test-ulps b/sysdeps/microblaze/libm-test-ulps
> diff --git a/sysdeps/mips/mips32/libm-test-ulps b/sysdeps/mips/mips32/libm-test-ulps
> diff --git a/sysdeps/mips/mips64/libm-test-ulps b/sysdeps/mips/mips64/libm-test-ulps
> diff --git a/sysdeps/or1k/fpu/libm-test-ulps b/sysdeps/or1k/fpu/libm-test-ulps
> diff --git a/sysdeps/or1k/nofpu/libm-test-ulps b/sysdeps/or1k/nofpu/libm-test-ulps
> diff --git a/sysdeps/powerpc/fpu/libm-test-ulps b/sysdeps/powerpc/fpu/libm-test-ulps
> diff --git a/sysdeps/powerpc/nofpu/libm-test-ulps b/sysdeps/powerpc/nofpu/libm-test-ulps
> diff --git a/sysdeps/riscv/nofpu/libm-test-ulps b/sysdeps/riscv/nofpu/libm-test-ulps
> diff --git a/sysdeps/riscv/rvd/libm-test-ulps b/sysdeps/riscv/rvd/libm-test-ulps
> diff --git a/sysdeps/s390/fpu/libm-test-ulps b/sysdeps/s390/fpu/libm-test-ulps
> diff --git a/sysdeps/sh/libm-test-ulps b/sysdeps/sh/libm-test-ulps
> diff --git a/sysdeps/sparc/fpu/libm-test-ulps b/sysdeps/sparc/fpu/libm-test-ulps
> diff --git a/sysdeps/x86_64/fpu/libm-test-ulps b/sysdeps/x86_64/fpu/libm-test-ulps

Ok.



More information about the Libc-alpha mailing list