aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config.mk.dist2
-rw-r--r--math/expf.c9
-rw-r--r--math/math_config.h39
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)
{