Fix fma overflow results outside round-to-nearest mode (bug 14797).

This commit is contained in:
Joseph Myers 2012-11-04 19:26:02 +00:00
parent b830319d49
commit a0c2940d67
6 changed files with 66 additions and 13 deletions

View file

@ -1,3 +1,15 @@
2012-11-04 Joseph Myers <joseph@codesourcery.com>
[BZ #14797]
* sysdeps/ieee754/dbl-64/s_fma.c (__fma): Compute cases that
definitely overflow as x * y not x * y + z.
* sysdeps/ieee754/ldbl-128/s_fmal.c (__fmal): Likewise.
* sysdeps/ieee754/ldbl-96/s_fmal.c (__fmal): Likewise.
* math/libm-test.inc (fma_test): Add more tests.
(fma_test_towardzero): Likewise.
(fma_test_downward): Likewise.
(fma_test_upward): Likewise.
2012-11-04 Thomas Schwinge <thomas@codesourcery.com>
[BZ #157]

2
NEWS
View file

@ -18,7 +18,7 @@ Version 2.17
14530, 14532, 14538, 14543, 14544, 14545, 14557, 14562, 14568, 14576,
14579, 14583, 14587, 14595, 14602, 14610, 14621, 14638, 14645, 14648,
14652, 14660, 14661, 14669, 14683, 14694, 14716, 14743, 14767, 14783,
14784, 14785, 14796.
14784, 14785, 14796, 14797.
* Support for STT_GNU_IFUNC symbols added for s390 and s390x.
Optimized versions of memcpy, memset, and memcmp added for System z10 and

View file

@ -4617,6 +4617,15 @@ fma_test (void)
TEST_fff_f (fma, -min_value, -min_value, plus_zero, plus_zero, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, -min_value, -min_value, minus_zero, plus_zero, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, max_value, min_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, max_value, -min_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, -max_value, min_value, minus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, -max_value, -min_value, minus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, max_value, min_value, minus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, max_value, -min_value, minus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, -max_value, min_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, -max_value, -min_value, plus_infty, OVERFLOW_EXCEPTION);
#if defined (TEST_FLOAT) && FLT_MANT_DIG == 24
TEST_fff_f (fma, 0x1.7ff8p+13, 0x1.000002p+0, 0x1.ffffp-24, 0x1.7ff802p+13);
TEST_fff_f (fma, 0x1.fffp+0, 0x1.00001p+0, -0x1.fffp+0, 0x1.fffp-20);
@ -4837,6 +4846,15 @@ fma_test_towardzero (void)
TEST_fff_f (fma, -min_value, -min_value, plus_zero, plus_zero, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, -min_value, -min_value, minus_zero, plus_zero, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, max_value, min_value, max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, max_value, -min_value, max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, -max_value, min_value, -max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, -max_value, -min_value, -max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, max_value, min_value, -max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, max_value, -min_value, -max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, -max_value, min_value, max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, -max_value, -min_value, max_value, OVERFLOW_EXCEPTION);
#if defined (TEST_FLOAT) && FLT_MANT_DIG == 24
TEST_fff_f (fma, 0x1.4p-126, 0x1.000004p-1, 0x1p-128, 0x1.c00004p-127, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, -0x1.4p-126, 0x1.000004p-1, -0x1p-128, -0x1.c00004p-127, UNDERFLOW_EXCEPTION);
@ -5014,6 +5032,15 @@ fma_test_downward (void)
TEST_fff_f (fma, -min_value, -min_value, plus_zero, plus_zero, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, -min_value, -min_value, minus_zero, plus_zero, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, max_value, min_value, max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, max_value, -min_value, max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, -max_value, min_value, minus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, -max_value, -min_value, minus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, max_value, min_value, minus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, max_value, -min_value, minus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, -max_value, min_value, max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, -max_value, -min_value, max_value, OVERFLOW_EXCEPTION);
#if defined (TEST_FLOAT) && FLT_MANT_DIG == 24
TEST_fff_f (fma, 0x1.4p-126, 0x1.000004p-1, 0x1p-128, 0x1.c00004p-127, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, -0x1.4p-126, 0x1.000004p-1, -0x1p-128, -0x1.c00008p-127, UNDERFLOW_EXCEPTION);
@ -5191,6 +5218,15 @@ fma_test_upward (void)
TEST_fff_f (fma, -min_value, -min_value, plus_zero, min_subnorm_value, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, -min_value, -min_value, minus_zero, min_subnorm_value, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, max_value, min_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, max_value, -min_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, -max_value, min_value, -max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, max_value, -max_value, -min_value, -max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, max_value, min_value, -max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, max_value, -min_value, -max_value, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, -max_value, min_value, plus_infty, OVERFLOW_EXCEPTION);
TEST_fff_f (fma, -max_value, -max_value, -min_value, plus_infty, OVERFLOW_EXCEPTION);
#if defined (TEST_FLOAT) && FLT_MANT_DIG == 24
TEST_fff_f (fma, 0x1.4p-126, 0x1.000004p-1, 0x1p-128, 0x1.c00008p-127, UNDERFLOW_EXCEPTION);
TEST_fff_f (fma, -0x1.4p-126, 0x1.000004p-1, -0x1p-128, -0x1.c00004p-127, UNDERFLOW_EXCEPTION);

View file

@ -55,16 +55,17 @@ __fma (double x, double y, double z)
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 zero, compute as x * y + z. */
/* If x or y or z is Inf/NaN, or if x * y is zero, compute as
x * y + z. */
if (u.ieee.exponent == 0x7ff
|| v.ieee.exponent == 0x7ff
|| w.ieee.exponent == 0x7ff
|| u.ieee.exponent + v.ieee.exponent
> 0x7ff + IEEE754_DOUBLE_BIAS
|| x == 0
|| y == 0)
return x * y + z;
/* If fma will certainly overflow, compute as x * y. */
if (u.ieee.exponent + v.ieee.exponent > 0x7ff + IEEE754_DOUBLE_BIAS)
return x * y;
/* If x * y is less than 1/4 of DBL_DENORM_MIN, neither the
result nor whether there is underflow depends on its exact
value, only on its sign. */

View file

@ -56,16 +56,18 @@ __fmal (long double x, long double y, long double z)
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 zero, compute as x * y + z. */
/* If x or y or z is Inf/NaN, or if x * y is zero, compute as
x * y + z. */
if (u.ieee.exponent == 0x7fff
|| v.ieee.exponent == 0x7fff
|| w.ieee.exponent == 0x7fff
|| u.ieee.exponent + v.ieee.exponent
> 0x7fff + IEEE854_LONG_DOUBLE_BIAS
|| x == 0
|| y == 0)
return x * y + z;
/* If fma will certainly overflow, compute as x * y. */
if (u.ieee.exponent + v.ieee.exponent
> 0x7fff + IEEE854_LONG_DOUBLE_BIAS)
return x * y;
/* If x * y is less than 1/4 of LDBL_DENORM_MIN, neither the
result nor whether there is underflow depends on its exact
value, only on its sign. */

View file

@ -56,16 +56,18 @@ __fmal (long double x, long double y, long double z)
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 zero, compute as x * y + z. */
/* If x or y or z is Inf/NaN, or if x * y is zero, compute as
x * y + z. */
if (u.ieee.exponent == 0x7fff
|| v.ieee.exponent == 0x7fff
|| w.ieee.exponent == 0x7fff
|| u.ieee.exponent + v.ieee.exponent
> 0x7fff + IEEE854_LONG_DOUBLE_BIAS
|| x == 0
|| y == 0)
return x * y + z;
/* If fma will certainly overflow, compute as x * y. */
if (u.ieee.exponent + v.ieee.exponent
> 0x7fff + IEEE854_LONG_DOUBLE_BIAS)
return x * y;
/* If x * y is less than 1/4 of LDBL_DENORM_MIN, neither the
result nor whether there is underflow depends on its exact
value, only on its sign. */