diff options
author | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2018-07-03 11:35:57 +0100 |
---|---|---|
committer | Szabolcs Nagy <szabolcs.nagy@arm.com> | 2018-07-03 12:59:23 +0100 |
commit | 2105bad5901834fa5ac38c16d8b6ce70a887caf4 (patch) | |
tree | e41407a9587c6402bc056a66daf3a791df1e592a /math/pow.c | |
parent | 58ce45c060855f525a26760a2aff22d30bbce7e9 (diff) | |
download | arm-optimized-routines-2105bad5901834fa5ac38c16d8b6ce70a887caf4.tar.gz |
Fix large ulp error in pow without fma very near 1.0
The !HAVE_FAST_FMA code path split r = z/c - 1 into r = rhi + rlo such
that when z = 1-tiny and c = 1 then rlo and rhi could have much larger
magnitude than r which later caused large rounding errors.
So do a nearest rounding instead of truncation at the split.
Diffstat (limited to 'math/pow.c')
-rw-r--r-- | math/pow.c | 6 |
1 files changed, 4 insertions, 2 deletions
@@ -67,11 +67,13 @@ log_inline (uint64_t ix, double_t *tail) logc = T[i].logc; logctail = T[i].logctail; - /* r = z/c - 1, arranged to be exact. */ + /* Note: 1/c is j/N or j/N/2 where j is an integer in [N,2N) and + |z/c - 1| < 1/N, so r = z/c - 1 is exactly representible. */ #if HAVE_FAST_FMA r = fma (z, invc, -1.0); #else - double_t zhi = asdouble (iz & (-1ULL << 32)); + /* Split z such that rhi, rlo and rhi*rhi are exact and |rlo| <= |r|. */ + double_t zhi = asdouble ((iz + (1ULL << 31)) & (-1ULL << 32)); double_t zlo = z - zhi; double_t rhi = zhi * invc - 1.0; double_t rlo = zlo * invc; |