aboutsummaryrefslogtreecommitdiff
path: root/libquadmath/math/fmaq.c
diff options
context:
space:
mode:
Diffstat (limited to 'libquadmath/math/fmaq.c')
-rw-r--r--libquadmath/math/fmaq.c36
1 files changed, 20 insertions, 16 deletions
diff --git a/libquadmath/math/fmaq.c b/libquadmath/math/fmaq.c
index 126b0a2d26b..23e3188669e 100644
--- a/libquadmath/math/fmaq.c
+++ b/libquadmath/math/fmaq.c
@@ -1,5 +1,5 @@
/* Compute x * y + z as ternary operation.
- Copyright (C) 2010 Free Software Foundation, Inc.
+ Copyright (C) 2010-2012 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Jakub Jelinek <jakub@redhat.com>, 2010.
@@ -57,6 +57,11 @@ fmaq (__float128 x, __float128 y, __float128 z)
&& u.ieee.exponent != 0x7fff
&& v.ieee.exponent != 0x7fff)
return (z + x) + y;
+ /* If z is zero and x are y are nonzero, compute the result
+ as x * y to avoid the wrong sign of a zero result if x * y
+ underflows to 0. */
+ if (z == 0 && x != 0 && y != 0)
+ return x * y;
/* If x or y or z is Inf/NaN, or if fma will certainly overflow,
or if x * y is less than half of FLT128_DENORM_MIN,
compute as x * y + z. */
@@ -136,6 +141,11 @@ fmaq (__float128 x, __float128 y, __float128 z)
y = v.value;
z = w.value;
}
+
+ /* Ensure correct sign of exact 0 + 0. */
+ if (__builtin_expect ((x == 0 || y == 0) && z == 0, 0))
+ return x * y + z;
+
/* Multiplication m1 + m2 = x * y using Dekker's algorithm. */
#define C ((1LL << (FLT128_MANT_DIG + 1) / 2) + 1)
__float128 x1 = x * C;
@@ -191,7 +201,7 @@ fmaq (__float128 x, __float128 y, __float128 z)
#endif
v.value = a1 + u.value;
/* Ensure the addition is not scheduled after fetestexcept call. */
- asm volatile ("" : : "m" (v));
+ asm volatile ("" : : "m" (v.value));
#ifdef USE_FENV_H
int j = fetestexcept (FE_INEXACT) != 0;
feupdateenv (&env);
@@ -220,20 +230,14 @@ fmaq (__float128 x, __float128 y, __float128 z)
{
/* v.ieee.mant_low & 2 is LSB bit of the result before rounding,
v.ieee.mant_low & 1 is the round bit and j is our sticky
- bit. In round-to-nearest 001 rounds down like 00,
- 011 rounds up, even though 01 rounds down (thus we need
- to adjust), 101 rounds down like 10 and 111 rounds up
- like 11. */
- if ((v.ieee.mant_low & 3) == 1)
- {
- v.value *= 0x1p-226Q;
- if (v.ieee.negative)
- return v.value - 0x1p-16494Q /* __FLT128_DENORM_MIN__ */;
- else
- return v.value + 0x1p-16494Q /* __FLT128_DENORM_MIN__ */;
- }
- else
- return v.value * 0x1p-226Q;
+ bit. */
+ w.value = 0.0Q;
+ w.ieee.mant_low = ((v.ieee.mant_low & 3) << 1) | j;
+ w.ieee.negative = v.ieee.negative;
+ v.ieee.mant_low &= ~3U;
+ v.value *= 0x1p-226L;
+ w.value *= 0x1p-2L;
+ return v.value + w.value;
}
v.ieee.mant_low |= j;
return v.value * 0x1p-226Q;