diff options
-rw-r--r-- | config.mk.dist | 2 | ||||
-rw-r--r-- | math/expf.c | 9 | ||||
-rw-r--r-- | math/math_config.h | 39 |
3 files changed, 28 insertions, 22 deletions
diff --git a/config.mk.dist b/config.mk.dist index a17fa9d..b616a65 100644 --- a/config.mk.dist +++ b/config.mk.dist @@ -25,7 +25,7 @@ CFLAGS += -Wall -Wno-missing-braces -Wno-strict-aliasing -Wno-unused-function # Use with gcc. CFLAGS += -frounding-math -fexcess-precision=standard -fno-stack-protector -CFLAGS += -ffp-contract=fast +CFLAGS += -ffp-contract=fast -fno-math-errno # Use with clang. #CFLAGS += -DCLANG_EXCEPTIONS diff --git a/math/expf.c b/math/expf.c index 90fd3b7..5d42b76 100644 --- a/math/expf.c +++ b/math/expf.c @@ -77,15 +77,12 @@ expf (float x) z = InvLn2N * xd; /* Round and convert z to int, the result is in [-150*N, 128*N] and - ideally ties-to-even rule is used, otherwise the magnitude of r - can be bigger which gives larger approximation error. */ + ideally nearest int is used, otherwise the magnitude of r can be + bigger which gives larger approximation error. */ #if TOINT_INTRINSICS kd = roundtoint (z); ki = converttoint (z); -#elif TOINT_RINT - kd = rint (z); - ki = (long) kd; -#elif TOINT_SHIFT +#else # define SHIFT __exp2f_data.shift kd = (double) (z + SHIFT); /* Rounding to double precision is required. */ ki = asuint64 (kd); diff --git a/math/math_config.h b/math/math_config.h index 4e0f643..70bd6c0 100644 --- a/math/math_config.h +++ b/math/math_config.h @@ -36,35 +36,44 @@ # define WANT_ERRNO_UFLOW (WANT_ROUNDING && WANT_ERRNO) #endif -#ifdef __aarch64__ -# include <arm_neon.h> +/* Compiler can inline round as a single instruction. */ +#ifndef HAVE_FAST_ROUND +# if __aarch64__ +# define HAVE_FAST_ROUND 1 +# else +# define HAVE_FAST_ROUND 0 +# endif +#endif + +/* Compiler can inline lround, but not (long)round(x). */ +#ifndef HAVE_FAST_LROUND +# if __aarch64__ && (100*__GNUC__ + __GNUC_MINOR__) >= 408 && __NO_MATH_ERRNO__ +# define HAVE_FAST_LROUND 1 +# else +# define HAVE_FAST_LROUND 0 +# endif +#endif -/* ACLE intrinsics for frintn and fcvtns instructions. */ +#if HAVE_FAST_ROUND # define TOINT_INTRINSICS 1 static inline double_t roundtoint (double_t x) { - return vget_lane_f64 (vrndn_f64 (vld1_f64 (&x)), 0); + return round (x); } static inline uint64_t converttoint (double_t x) { - return vcvtnd_s64_f64 (x); +# if HAVE_FAST_LROUND + return lround (x); +# else + return (long) round (x); +# endif } #endif -#ifndef TOINT_INTRINSICS -# define TOINT_INTRINSICS 0 -#endif -#ifndef TOINT_RINT -# define TOINT_RINT 0 -#endif -#ifndef TOINT_SHIFT -# define TOINT_SHIFT 1 -#endif - static inline uint32_t asuint (float f) { |