diff options
Diffstat (limited to 'tests/tfmma.c')
-rw-r--r-- | tests/tfmma.c | 283 |
1 files changed, 262 insertions, 21 deletions
diff --git a/tests/tfmma.c b/tests/tfmma.c index b825de646..c45995a57 100644 --- a/tests/tfmma.c +++ b/tests/tfmma.c @@ -22,8 +22,6 @@ http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., #include "mpfr-test.h" -/* TODO: add more tests, with special values and exception checking. */ - /* check both mpfr_fmma and mpfr_fmms */ static void random_test (mpfr_t a, mpfr_t b, mpfr_t c, mpfr_t d, mpfr_rnd_t rnd) @@ -123,7 +121,7 @@ zero_tests (void) set_emin (MPFR_EMIN_MIN); set_emax (MPFR_EMAX_MAX); - mpfr_inits2 (64, a, b, c, d, res, (mpfr_ptr) 0); + mpfr_inits2 (GMP_NUMB_BITS, a, b, c, d, (mpfr_ptr) 0); for (i = 0; i <= 4; i++) { switch (i) @@ -143,38 +141,278 @@ zero_tests (void) } RND_LOOP (r) { - int inex; + int j, inex; mpfr_flags_t flags; mpfr_set (b, a, MPFR_RNDN); mpfr_set (c, a, MPFR_RNDN); mpfr_neg (d, a, MPFR_RNDN); + /* We also want to test cases where the precision of the + result is twice the precision of each input, in case + add1sp.c and/or sub1sp.c could be involved. */ + for (j = 1; j <= 2; j++) + { + mpfr_init2 (res, GMP_NUMB_BITS * j); + mpfr_clear_flags (); + inex = mpfr_fmma (res, a, b, c, d, (mpfr_rnd_t) r); + flags = __gmpfr_flags; + if (flags != 0 || inex != 0 || ! mpfr_zero_p (res) || + (r == MPFR_RNDD ? MPFR_IS_POS (res) : MPFR_IS_NEG (res))) + { + printf ("Error in zero_tests on i = %d, %s\n", + i, mpfr_print_rnd_mode ((mpfr_rnd_t) r)); + printf ("Expected %c0, inex = 0\n", + r == MPFR_RNDD ? '-' : '+'); + printf ("Got "); + if (MPFR_IS_POS (res)) + printf ("+"); + mpfr_out_str (stdout, 16, 0, res, MPFR_RNDN); + printf (", inex = %d\n", inex); + printf ("Expected flags:"); + flags_out (0); + printf ("Got flags: "); + flags_out (flags); + exit (1); + } + mpfr_clear (res); + } /* j */ + } /* r */ + } /* i */ + mpfr_clears (a, b, c, d, (mpfr_ptr) 0); + + set_emin (emin); + set_emax (emax); +} + +static void +max_tests (void) +{ + mpfr_exp_t emin, emax; + mpfr_t x, y1, y2; + int r; + int i, inex1, inex2; + mpfr_flags_t flags1, flags2; + + emin = mpfr_get_emin (); + emax = mpfr_get_emax (); + set_emin (MPFR_EMIN_MIN); + set_emax (MPFR_EMAX_MAX); + + mpfr_init2 (x, GMP_NUMB_BITS); + mpfr_setmax (x, MPFR_EMAX_MAX); + flags1 = MPFR_FLAGS_OVERFLOW | MPFR_FLAGS_INEXACT; + RND_LOOP (r) + { + /* We also want to test cases where the precision of the + result is twice the precision of each input, in case + add1sp.c and/or sub1sp.c could be involved. */ + for (i = 1; i <= 2; i++) + { + mpfr_inits2 (GMP_NUMB_BITS * i, y1, y2, (mpfr_ptr) 0); + inex1 = mpfr_mul (y1, x, x, (mpfr_rnd_t) r); mpfr_clear_flags (); - inex = mpfr_fmma (res, a, b, c, d, (mpfr_rnd_t) r); - flags = __gmpfr_flags; - if (flags != 0 || inex != 0 || ! mpfr_zero_p (res) || - (r == MPFR_RNDD ? MPFR_IS_POS (res) : MPFR_IS_NEG (res))) + inex2 = mpfr_fmma (y2, x, x, x, x, (mpfr_rnd_t) r); + flags2 = __gmpfr_flags; + if (! (flags1 == flags2 && SAME_SIGN (inex1, inex2) && + mpfr_equal_p (y1, y2))) { - printf ("Error in zero_tests on i = %d, %s\n", - i, mpfr_print_rnd_mode ((mpfr_rnd_t) r)); - printf ("Expected %c0, inex = 0\n", r == MPFR_RNDD ? '-' : '+'); + printf ("Error in max_tests for %s\n", + mpfr_print_rnd_mode ((mpfr_rnd_t) r)); + printf ("Expected "); + mpfr_dump (y1); + printf (" with inex = %d, flags =", inex1); + flags_out (flags1); printf ("Got "); - if (MPFR_IS_POS (res)) - printf ("+"); - mpfr_out_str (stdout, 16, 0, res, MPFR_RNDN); - printf (", inex = %d\n", inex); - printf ("Expected flags:"); - flags_out (0); - printf ("Got flags: "); - flags_out (flags); + mpfr_dump (y2); + printf (" with inex = %d, flags =", inex2); + flags_out (flags2); exit (1); } + mpfr_clears (y1, y2, (mpfr_ptr) 0); + } /* i */ + } /* r */ + mpfr_clear (x); + + set_emin (emin); + set_emax (emax); +} + +/* a^2 - (a+k)(a-k) = k^2 where a^2 overflows but k^2 usually doesn't. + * a^2 + cd where a^2 overflows and cd doesn't affect the overflow + * (and cd may even underflow). + */ +static void +overflow_tests (void) +{ + mpfr_exp_t old_emax; + int i; + + old_emax = mpfr_get_emax (); + + for (i = 0; i < 40; i++) + { + mpfr_exp_t emax, exp_a; + mpfr_t a, k, c, d, z1, z2; + mpfr_rnd_t rnd; + mpfr_prec_t prec_a, prec_z; + int add = i & 1, inex, inex1, inex2; + mpfr_flags_t flags1, flags2; + + /* In most cases, we do the test with the maximum exponent. */ + emax = i % 8 != 0 ? MPFR_EMAX_MAX : 64 + (randlimb () % 1); + set_emax (emax); + exp_a = emax/2 + 32; + + rnd = RND_RAND (); + prec_a = 64 + randlimb () % 100; + prec_z = MPFR_PREC_MIN + randlimb () % 160; + + mpfr_init2 (a, prec_a); + mpfr_urandom (a, RANDS, MPFR_RNDU); + mpfr_set_exp (a, exp_a); + + mpfr_init2 (k, prec_a - 32); + mpfr_urandom (k, RANDS, MPFR_RNDU); + mpfr_set_exp (k, exp_a - 32); + + mpfr_init2 (c, prec_a + 1); + inex = mpfr_add (c, a, k, MPFR_RNDN); + MPFR_ASSERTN (inex == 0); + + mpfr_init2 (d, prec_a); + inex = mpfr_sub (d, a, k, MPFR_RNDN); + MPFR_ASSERTN (inex == 0); + if (add) + mpfr_neg (d, d, MPFR_RNDN); + + mpfr_init2 (z1, prec_z); + mpfr_clear_flags (); + inex1 = mpfr_sqr (z1, k, rnd); + flags1 = __gmpfr_flags; + + mpfr_init2 (z2, prec_z); + mpfr_clear_flags (); + inex2 = add ? + mpfr_fmma (z2, a, a, c, d, rnd) : + mpfr_fmms (z2, a, a, c, d, rnd); + flags2 = __gmpfr_flags; + + if (! (flags1 == flags2 && SAME_SIGN (inex1, inex2) && + mpfr_equal_p (z1, z2))) + { + printf ("Error 1 in overflow_tests for %s\n", + mpfr_print_rnd_mode (rnd)); + printf ("Expected "); + mpfr_dump (z1); + printf (" with inex = %d, flags =", inex1); + flags_out (flags1); + printf ("Got "); + mpfr_dump (z2); + printf (" with inex = %d, flags =", inex2); + flags_out (flags2); + exit (1); + } + + /* c and d such that a^2 +/- cd ~= a^2 (overflow) */ + mpfr_urandom (c, RANDS, MPFR_RNDU); + mpfr_set_exp (c, randlimb () % 1 ? exp_a - 2 : __gmpfr_emin); + if (randlimb () % 1) + mpfr_neg (c, c, MPFR_RNDN); + mpfr_urandom (d, RANDS, MPFR_RNDU); + mpfr_set_exp (d, randlimb () % 1 ? exp_a - 2 : __gmpfr_emin); + if (randlimb () % 1) + mpfr_neg (d, d, MPFR_RNDN); + + mpfr_clear_flags (); + inex1 = mpfr_sqr (z1, a, rnd); + flags1 = __gmpfr_flags; + MPFR_ASSERTN (flags1 == (MPFR_FLAGS_OVERFLOW | MPFR_FLAGS_INEXACT)); + + mpfr_clear_flags (); + inex2 = add ? + mpfr_fmma (z2, a, a, c, d, rnd) : + mpfr_fmms (z2, a, a, c, d, rnd); + flags2 = __gmpfr_flags; + + if (! (flags1 == flags2 && SAME_SIGN (inex1, inex2) && + mpfr_equal_p (z1, z2))) + { + printf ("Error 2 in overflow_tests for %s\n", + mpfr_print_rnd_mode (rnd)); + printf ("Expected "); + mpfr_dump (z1); + printf (" with inex = %d, flags =", inex1); + flags_out (flags1); + printf ("Got "); + mpfr_dump (z2); + printf (" with inex = %d, flags =", inex2); + flags_out (flags2); + exit (1); + } + + mpfr_clears (a, k, c, d, z1, z2, (mpfr_ptr) 0); + } + + set_emax (old_emax); +} + +/* (1/2)x + (1/2)x = x tested near underflow */ +static void +half_plus_half (void) +{ + mpfr_exp_t emin; + mpfr_t h, x1, x2, y; + int neg, r, i, inex; + mpfr_flags_t flags; + + emin = mpfr_get_emin (); + set_emin (MPFR_EMIN_MIN); + mpfr_inits2 (4, h, x1, (mpfr_ptr) 0); + mpfr_init2 (x2, GMP_NUMB_BITS); + mpfr_set_ui_2exp (h, 1, -1, MPFR_RNDN); + + for (mpfr_setmin (x1, __gmpfr_emin); + MPFR_GET_EXP (x1) < __gmpfr_emin + 2; + mpfr_nextabove (x1)) + { + inex = mpfr_set (x2, x1, MPFR_RNDN); + MPFR_ASSERTN (inex == 0); + for (neg = 0; neg < 2; neg++) + { + RND_LOOP (r) + { + /* We also want to test cases where the precision of the + result is twice the precision of each input, in case + add1sp.c and/or sub1sp.c could be involved. */ + for (i = 1; i <= 2; i++) + { + mpfr_init2 (y, GMP_NUMB_BITS * i); + mpfr_clear_flags (); + inex = mpfr_fmma (y, h, x2, h, x2, (mpfr_rnd_t) r); + flags = __gmpfr_flags; + if (! (flags == 0 && inex == 0 && mpfr_equal_p (y, x2))) + { + printf ("Error in half_plus_half for %s\n", + mpfr_print_rnd_mode ((mpfr_rnd_t) r)); + printf ("Expected "); + mpfr_dump (x2); + printf (" with inex = 0, flags ="); + flags_out (0); + printf ("Got "); + mpfr_dump (y); + printf (" with inex = %d, flags =", inex); + flags_out (flags); + exit (1); + } + mpfr_clear (y); + } + } + mpfr_neg (x2, x2, MPFR_RNDN); } } - mpfr_clears (a, b, c, d, res, (mpfr_ptr) 0); + mpfr_clears (h, x1, x2, (mpfr_ptr) 0); set_emin (emin); - set_emax (emax); } int @@ -184,6 +422,9 @@ main (int argc, char *argv[]) random_tests (); zero_tests (); + max_tests (); + overflow_tests (); + half_plus_half (); tests_end_mpfr (); return 0; |