mirror of
https://review.haiku-os.org/buildtools
synced 2025-02-07 14:34:51 +01:00
974e12c1f0
Old version was 3.1.2 and is quite old: 2013-03-13 A lot has happened since then 4.0.1 is from 2018-02-07
487 lines
17 KiB
C
487 lines
17 KiB
C
/* Test file for mpfr_fmma and mpfr_fmms.
|
|
|
|
Copyright 2016-2018 Free Software Foundation, Inc.
|
|
Contributed by the AriC and Caramba projects, INRIA.
|
|
|
|
This file is part of the GNU MPFR Library.
|
|
|
|
The GNU MPFR Library is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU Lesser General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or (at your
|
|
option) any later version.
|
|
|
|
The GNU MPFR Library is distributed in the hope that it will be useful, but
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
|
License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
|
|
http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
|
|
51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
|
|
|
|
#include "mpfr-test.h"
|
|
|
|
/* 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)
|
|
{
|
|
mpfr_t ref, res, ab, cd;
|
|
int inex_ref, inex_res;
|
|
mpfr_prec_t p = MPFR_PREC(a);
|
|
|
|
mpfr_init2 (res, p);
|
|
mpfr_init2 (ref, p);
|
|
mpfr_init2 (ab, mpfr_get_prec (a) + mpfr_get_prec (b));
|
|
mpfr_init2 (cd, mpfr_get_prec (c) + mpfr_get_prec (d));
|
|
|
|
/* first check fmma */
|
|
inex_res = mpfr_fmma (res, a, b, c, d, rnd);
|
|
mpfr_mul (ab, a, b, rnd);
|
|
mpfr_mul (cd, c, d, rnd);
|
|
inex_ref = mpfr_add (ref, ab, cd, rnd);
|
|
if (! SAME_SIGN (inex_res, inex_ref) ||
|
|
mpfr_nan_p (res) || mpfr_nan_p (ref) ||
|
|
! mpfr_equal_p (res, ref))
|
|
{
|
|
printf ("mpfr_fmma failed for p=%ld rnd=%s\n",
|
|
(long int) p, mpfr_print_rnd_mode (rnd));
|
|
printf ("a="); mpfr_dump (a);
|
|
printf ("b="); mpfr_dump (b);
|
|
printf ("c="); mpfr_dump (c);
|
|
printf ("d="); mpfr_dump (d);
|
|
printf ("Expected\n ");
|
|
mpfr_dump (ref);
|
|
printf (" with inex = %d\n", inex_ref);
|
|
printf ("Got\n ");
|
|
mpfr_dump (res);
|
|
printf (" with inex = %d\n", inex_res);
|
|
exit (1);
|
|
}
|
|
|
|
/* then check fmms */
|
|
inex_res = mpfr_fmms (res, a, b, c, d, rnd);
|
|
mpfr_mul (ab, a, b, rnd);
|
|
mpfr_mul (cd, c, d, rnd);
|
|
inex_ref = mpfr_sub (ref, ab, cd, rnd);
|
|
if (! SAME_SIGN (inex_res, inex_ref) ||
|
|
mpfr_nan_p (res) || mpfr_nan_p (ref) ||
|
|
! mpfr_equal_p (res, ref))
|
|
{
|
|
printf ("mpfr_fmms failed for p=%ld rnd=%s\n",
|
|
(long int) p, mpfr_print_rnd_mode (rnd));
|
|
printf ("a="); mpfr_dump (a);
|
|
printf ("b="); mpfr_dump (b);
|
|
printf ("c="); mpfr_dump (c);
|
|
printf ("d="); mpfr_dump (d);
|
|
printf ("Expected\n ");
|
|
mpfr_dump (ref);
|
|
printf (" with inex = %d\n", inex_ref);
|
|
printf ("Got\n ");
|
|
mpfr_dump (res);
|
|
printf (" with inex = %d\n", inex_res);
|
|
exit (1);
|
|
}
|
|
|
|
mpfr_clear (ab);
|
|
mpfr_clear (cd);
|
|
mpfr_clear (res);
|
|
mpfr_clear (ref);
|
|
}
|
|
|
|
static void
|
|
random_tests (void)
|
|
{
|
|
mpfr_prec_t p;
|
|
int r;
|
|
mpfr_t a, b, c, d;
|
|
|
|
for (p = MPFR_PREC_MIN; p <= 4096; p++)
|
|
{
|
|
mpfr_inits2 (p, a, b, c, d, (mpfr_ptr) 0);
|
|
mpfr_urandomb (a, RANDS);
|
|
mpfr_urandomb (b, RANDS);
|
|
mpfr_urandomb (c, RANDS);
|
|
mpfr_urandomb (d, RANDS);
|
|
RND_LOOP_NO_RNDF (r)
|
|
random_test (a, b, c, d, (mpfr_rnd_t) r);
|
|
mpfr_clears (a, b, c, d, (mpfr_ptr) 0);
|
|
}
|
|
}
|
|
|
|
static void
|
|
zero_tests (void)
|
|
{
|
|
mpfr_exp_t emin, emax;
|
|
mpfr_t a, b, c, d, res;
|
|
int i, r;
|
|
|
|
emin = mpfr_get_emin ();
|
|
emax = mpfr_get_emax ();
|
|
set_emin (MPFR_EMIN_MIN);
|
|
set_emax (MPFR_EMAX_MAX);
|
|
|
|
mpfr_inits2 (GMP_NUMB_BITS, a, b, c, d, (mpfr_ptr) 0);
|
|
for (i = 0; i <= 4; i++)
|
|
{
|
|
switch (i)
|
|
{
|
|
case 0: case 1:
|
|
mpfr_set_ui (a, i, MPFR_RNDN);
|
|
break;
|
|
case 2:
|
|
mpfr_setmax (a, MPFR_EMAX_MAX);
|
|
break;
|
|
case 3:
|
|
mpfr_setmin (a, MPFR_EMIN_MIN);
|
|
break;
|
|
case 4:
|
|
mpfr_setmin (a, MPFR_EMIN_MIN+1);
|
|
break;
|
|
}
|
|
RND_LOOP (r)
|
|
{
|
|
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 ();
|
|
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 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 ");
|
|
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_NO_RNDF ();
|
|
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);
|
|
printf ("a="); mpfr_dump (a);
|
|
printf ("c="); mpfr_dump (c);
|
|
printf ("d="); mpfr_dump (d);
|
|
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 (h, x1, x2, (mpfr_ptr) 0);
|
|
set_emin (emin);
|
|
}
|
|
|
|
/* check that result has exponent in [emin, emax]
|
|
(see https://sympa.inria.fr/sympa/arc/mpfr/2017-04/msg00016.html)
|
|
Overflow detection in sub1.c was incorrect (only for UBF cases);
|
|
fixed in r11414. */
|
|
static void
|
|
bug20170405 (void)
|
|
{
|
|
mpfr_t x, y, z;
|
|
|
|
mpfr_inits2 (866, x, y, z, (mpfr_ptr) 0);
|
|
|
|
mpfr_set_str_binary (x, "-0.10010101110110001111000110010100011001111011110001010100010000111110001010111110100001000000011010001000010000101110000000001100001011000110010000100111001100000101110000000001001101101101010110000110100010010111011001101101010011111000101100000010001100010000011100000000011110100010111011101011000101101011110110001010011001101110011101100001111000011000000011000010101010000101001001010000111101100001000001011110011000110010001100001101101001001010000111100101000010111001001101010011001110110001000010101001100000101010110000100100100010101011111001001100010001010110011000000001011110011000110001000100101000111010010111111110010111001101110101010010101101010100111001011100101101010111010011001000001010011001010001101000111011010010100110011001111111000011101111001010111001001011011011110101101001100011010001010110011100001101100100001001100111010100010100E768635654");
|
|
mpfr_set_str_binary (y, "-0.11010001010111110010110101010011000010010011010011011101100100110000110101100110111010001001110101110000011101100010110100100011001101111010100011111001011100111101110101101001000101011110101101101011010100110010111111010011011100101111110011001001010101011101111100011101100001010010011000110010110101001110010001101111111001100100000101010100110011101101101010011001000110100001001100000010110010101111000110110000111011000110001000100100100101111110001111100101011100100100110111010000010110110001110010001001101000000110111000101000110101111110000110001110100010101111010110001111010111111111010011001001100110011000110010110011000101110001010001101000100010000110011101010010010011110100000111100000101100110001111010000100011111000001101111110100000011011110010100010010011111111000010110000000011010011001100110001110111111010111110000111110010110011001000010E768635576");
|
|
/* since emax = 1073741821, x^2-y^2 should overflow */
|
|
mpfr_fmms (z, x, x, y, y, MPFR_RNDN);
|
|
MPFR_ASSERTN(mpfr_inf_p (z) && mpfr_sgn (z) > 0);
|
|
|
|
/* same test when z has a different precision */
|
|
mpfr_set_prec (z, 867);
|
|
mpfr_fmms (z, x, x, y, y, MPFR_RNDN);
|
|
MPFR_ASSERTN(mpfr_inf_p (z) && mpfr_sgn (z) > 0);
|
|
|
|
mpfr_set_prec (x, 564);
|
|
mpfr_set_prec (y, 564);
|
|
mpfr_set_prec (z, 2256);
|
|
mpfr_set_str_binary (x, "1.10010000111100110011001101111111101000111001011000110100110010000101000100010001000000111100010000101001011011111001111000110101111100101111001100001100011101100100011110000000011000010110111100111000100101010001011111010111011001110010001011101111001011001110110000010000011100010001010001011100100110111110101001001111001011101111110011101110101010110100010010111011111100010101111100011110111001011111101110101101101110100101111010000101011110100000000110111101000001100001000100010110100111010011011010110011100111010000101110010101111001011100110101100001100e-737194993");
|
|
mpfr_set_str_binary (y, "-1.00101000100001001101011110100010110011101010011011010111100110101011111100000100101000111010111101100100110010001110011011100100110110000001011001000111101111101111110101100110111000000011000001101001010100010010001110001000011010000100111001001100101111111100010101110101001101101101111010100011011110001000010000010100011000011000010110101100000111111110111001100100100001101011111011100101110111000100101010110100010011101010110010100110100111000000100111101101101000000011110000100110100100011000010011110010001010000110100011111101101101110001110001101101010e-737194903");
|
|
mpfr_fmma (z, x, y, x, y, MPFR_RNDN);
|
|
/* we should get -0 as result */
|
|
MPFR_ASSERTN(mpfr_zero_p (z) && mpfr_signbit (z));
|
|
|
|
mpfr_set_prec (x, 2);
|
|
mpfr_set_prec (y, 2);
|
|
mpfr_set_prec (z, 2);
|
|
/* (a+i*b)*(c+i*d) with:
|
|
a=0.10E1
|
|
b=0.10E-536870912
|
|
c=0.10E-536870912
|
|
d=0.10E1 */
|
|
mpfr_set_str_binary (x, "0.10E1"); /* x = a = d */
|
|
mpfr_set_str_binary (y, "0.10E-536870912"); /* y = b = c */
|
|
/* real part is a*c-b*d = x*y-y*x */
|
|
mpfr_fmms (z, x, y, y, x, MPFR_RNDN);
|
|
MPFR_ASSERTN(mpfr_zero_p (z) && !mpfr_signbit (z));
|
|
/* imaginary part is a*d+b*c = x*x+y*y */
|
|
mpfr_fmma (z, x, x, y, y, MPFR_RNDN);
|
|
MPFR_ASSERTN(mpfr_cmp_ui (z, 1) == 0);
|
|
|
|
mpfr_clears (x, y, z, (mpfr_ptr) 0);
|
|
}
|
|
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
tests_start_mpfr ();
|
|
|
|
random_tests ();
|
|
zero_tests ();
|
|
max_tests ();
|
|
overflow_tests ();
|
|
half_plus_half ();
|
|
bug20170405 ();
|
|
|
|
tests_end_mpfr ();
|
|
return 0;
|
|
}
|