diff options
author | das <das@FreeBSD.org> | 2011-10-21 06:30:43 +0000 |
---|---|---|
committer | das <das@FreeBSD.org> | 2011-10-21 06:30:43 +0000 |
commit | 597452d19d2c874abf6e0c2f9ff1295c9ad157c1 (patch) | |
tree | 61f25cba269fd9ea7a9e512007292525d6413b6d /lib | |
parent | 5e302d8d6ba6877b2fd08509d5168ca989b444a3 (diff) | |
download | FreeBSD-src-597452d19d2c874abf6e0c2f9ff1295c9ad157c1.zip FreeBSD-src-597452d19d2c874abf6e0c2f9ff1295c9ad157c1.tar.gz |
Fix a regression introduced in r226371: When the high part of x*y
exactly cancels with z, return the low part of x*y instead of
discarding it.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/msun/src/s_fma.c | 6 | ||||
-rw-r--r-- | lib/msun/src/s_fmal.c | 6 |
2 files changed, 6 insertions, 6 deletions
diff --git a/lib/msun/src/s_fma.c b/lib/msun/src/s_fma.c index 9cb0ddc..dfbd13c 100644 --- a/lib/msun/src/s_fma.c +++ b/lib/msun/src/s_fma.c @@ -250,6 +250,8 @@ fma(double x, double y, double z) xy = dd_mul(xs, ys); r = dd_add(xy.hi, zs); + spread = ex + ey; + if (r.hi == 0.0) { /* * When the addends cancel to 0, ensure that the result has @@ -257,11 +259,9 @@ fma(double x, double y, double z) */ fesetround(oround); volatile double vzs = zs; /* XXX gcc CSE bug workaround */ - return (xy.hi + vzs); + return (xy.hi + vzs + ldexp(xy.lo, spread)); } - spread = ex + ey; - if (oround != FE_TONEAREST) { /* * There is no need to worry about double rounding in directed diff --git a/lib/msun/src/s_fmal.c b/lib/msun/src/s_fmal.c index 59fa6cd..c2a6913 100644 --- a/lib/msun/src/s_fmal.c +++ b/lib/msun/src/s_fmal.c @@ -238,6 +238,8 @@ fmal(long double x, long double y, long double z) xy = dd_mul(xs, ys); r = dd_add(xy.hi, zs); + spread = ex + ey; + if (r.hi == 0.0) { /* * When the addends cancel to 0, ensure that the result has @@ -245,11 +247,9 @@ fmal(long double x, long double y, long double z) */ fesetround(oround); volatile long double vzs = zs; /* XXX gcc CSE bug workaround */ - return (xy.hi + vzs); + return (xy.hi + vzs + ldexpl(xy.lo, spread)); } - spread = ex + ey; - if (oround != FE_TONEAREST) { /* * There is no need to worry about double rounding in directed |