aboutsummaryrefslogtreecommitdiff
path: root/math/expf.c
diff options
context:
space:
mode:
authorSzabolcs Nagy <szabolcs.nagy@arm.com>2018-05-10 15:35:06 +0100
committerSzabolcs Nagy <szabolcs.nagy@arm.com>2018-05-16 13:52:13 +0100
commit39b0191da32e494ca7d1e9991614d03f3126fd9f (patch)
tree93b7ae9ee8fa1ae936521da32fe0a982ab09b971 /math/expf.c
parent0d51c0453a46a76dcf3bfd1820de7e2ffbd4b751 (diff)
downloadarm-optimized-routines-39b0191da32e494ca7d1e9991614d03f3126fd9f.tar.gz
Clean up roundtoint and converttoint
Ideally single instruction is used for rounding and conversion that round to the nearest integer independently of the current rounding mode, otherwise the argument reduction in expf is not reducing into the optimal range in non-nearest rounding mode. AArch64 has the necessary instructions, both for rounding ties away from zero (round function in C) and rounding ties to even (roundeven function in TS 18661), originally the later was used, but the former can be expressed in portable C code without relying on ACLE intrinsics. A bit of complication is that round and lround are not always inlined as a single instruction: - gcc inlines lround with -fno-math-errno, but fails to inline (long)round as a single instruction (at least up to gcc-8). - clang inlines (long)round, but not lround. Portable code is still better than relying on arm_neon.h, so use the round function when it works and keep the shift based rounding as fallback (which only gives precise results in nearest rounding mode, but is the optimal implementation for most targets). HAVE_FAST_ROUND and HAVE_FAST_LROUND are set based on preprocessor heuristics (user can override them with CFLAGS) for now, once there is a configure script we can detect these at configure time.
Diffstat (limited to 'math/expf.c')
-rw-r--r--math/expf.c9
1 files changed, 3 insertions, 6 deletions
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);