buildtools/gcc/mpfr/tests/trandom_deviate.c
Fredrik Holmqvist 974e12c1f0 Upgrade mpfr to 4.0.1
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
2018-07-04 20:21:01 +02:00

323 lines
10 KiB
C

/* Test file for mpfr_random_deviate
Copyright 2011-2018 Free Software Foundation, Inc.
Contributed by Charles Karney <charles@karney.com>, SRI International.
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"
#include "random_deviate.h"
#define W 32 /* Must match value in random_deviate.c */
/* set random deviate rop from op */
static void
mpfr_random_deviate_set (mpfr_random_deviate_t rop, mpfr_random_deviate_t op)
{
rop->e = op->e;
rop->h = op->h;
mpz_set (rop->f, op->f);
}
/* set random deviate to fract * 2^-expt. expt must be a multiple
* of W and cannot be 0. fract must be in [0,2^W) */
static void
mpfr_random_deviate_ldexp (mpfr_random_deviate_t rop,
unsigned long fract, unsigned long expt)
{
rop->h = (expt > W ? 0ul : fract);
mpz_set_ui (rop->f, expt > W ? fract : 0ul);
rop->e = expt;
}
/* Test mpfr_random_deviate_less. With two initially equal deviates this
* should return true half the time. In order to execute additional code
* paths, the two deviates are repeatedly set equal and the test repeated (with
* now a longer fraction and with the test now triggering the sampling of an
* additional chunk. */
static void
test_compare (long nbtests, int verbose)
{
mpfr_random_deviate_t u, v;
int k, i, t1, t2;
long count;
mpfr_random_deviate_init (u);
mpfr_random_deviate_init (v);
count = 0;
for (k = 0; k < nbtests; ++k)
{
mpfr_random_deviate_reset (u);
mpfr_random_deviate_reset (v);
for (i = 0; i < 10; ++i)
{
t1 = mpfr_random_deviate_less (u, v, RANDS);
t2 = mpfr_random_deviate_less (u, v, RANDS);
if (t1 != t2)
{
printf ("Error: mpfr_random_deviate_less() inconsistent.\n");
exit (1);
}
if (t1)
++count;
/* Force the test to sample an additional chunk */
mpfr_random_deviate_set (u, v);
}
t1 = mpfr_random_deviate_less (u, u, RANDS);
if (t1)
{
printf ("Error: mpfr_random_deviate_less() gives u < u.\n");
exit (1);
}
t1 = mpfr_random_deviate_tstbit (u, 0, RANDS);
if (t1)
{
printf ("Error: mpfr_random_deviate_tstbit() says 1 bit is on.\n");
exit (1);
}
}
mpfr_random_deviate_clear (v);
mpfr_random_deviate_clear (u);
if (verbose)
printf ("Fraction of true random_deviate_less = %.4f"
" (should be about 0.5)\n",
count / (double) (10 * nbtests));
}
/* A random_deviate should consistently return the same value at a given
* precision, even if intervening operations have caused the fraction to be
* extended. */
static void
test_value_consistency (long nbtests)
{
mpfr_t a1, a2, a3, b1, b2, b3;
mpfr_random_deviate_t u;
int inexa1, inexa2, inexa3, inexb1, inexb2, inexb3;
mpfr_prec_t prec1, prec2, prec3;
mpfr_rnd_t rnd;
long i;
unsigned n;
int neg;
/* Pick prec{1,2,3} random in [2,101] */
prec1 = 2 + gmp_urandomm_ui (RANDS, 100);
prec2 = 2 + gmp_urandomm_ui (RANDS, 100);
prec3 = 2 + gmp_urandomm_ui (RANDS, 100);
rnd = MPFR_RNDN;
mpfr_random_deviate_init (u);
mpfr_init2 (a1, prec1);
mpfr_init2 (b1, prec1);
mpfr_init2 (a2, prec2);
mpfr_init2 (b2, prec2);
mpfr_init2 (a3, prec3);
mpfr_init2 (b3, prec3);
for (i = 0; i < nbtests; ++i)
{
mpfr_random_deviate_reset (u);
n = gmp_urandomb_ui (RANDS, 4);
neg = gmp_urandomb_ui (RANDS, 1);
inexa1 = mpfr_random_deviate_value (neg, n, u, a1, RANDS, rnd);
inexa2 = mpfr_random_deviate_value (neg, n, u, a2, RANDS, rnd);
inexa3 = mpfr_random_deviate_value (neg, n, u, a3, RANDS, rnd);
inexb1 = mpfr_random_deviate_value (neg, n, u, b1, RANDS, rnd);
inexb2 = mpfr_random_deviate_value (neg, n, u, b2, RANDS, rnd);
inexb3 = mpfr_random_deviate_value (neg, n, u, b3, RANDS, rnd);
/* Of course a1, a2, and a3 should all be nearly equal. But more
* crucially (and easier to test), we need a1 == b1, etc. (This is not a
* trivial issue because the detailed mpfr operations giving b1 will be
* different than for a1, if, e.g., prec2 > prec1. */
if ( !( inexa1 == inexb1 && mpfr_equal_p (a1, b1) &&
inexa2 == inexb2 && mpfr_equal_p (a2, b2) &&
inexa3 == inexb3 && mpfr_equal_p (a3, b3) ) )
{
printf ("Error: random_deviate values are inconsistent.\n");
exit (1);
}
}
mpfr_random_deviate_clear (u);
mpfr_clears (a1, a2, a3, b1, b2, b3, (mpfr_ptr) 0);
}
/* Check that the values from random_deviate with different rounding modes are
* consistent. */
static void
test_value_round (long nbtests, mpfr_prec_t prec)
{
mpfr_t xn, xd, xu, xz, xa, t;
mpfr_random_deviate_t u;
int inexn, inexd, inexu, inexz, inexa, inext;
long i;
unsigned n;
int neg, s;
mpfr_random_deviate_init (u);
mpfr_inits2 (prec, xn, xd, xu, xz, xa, t, (mpfr_ptr) 0);
for (i = 0; i < nbtests; ++i)
{
mpfr_random_deviate_reset (u);
n = gmp_urandomb_ui (RANDS, 4);
neg = gmp_urandomb_ui (RANDS, 1);
s = neg ? -1 : 1;
inexn = mpfr_random_deviate_value (neg, n, u, xn, RANDS, MPFR_RNDN);
inexd = mpfr_random_deviate_value (neg, n, u, xd, RANDS, MPFR_RNDD);
inexu = mpfr_random_deviate_value (neg, n, u, xu, RANDS, MPFR_RNDU);
inexz = mpfr_random_deviate_value (neg, n, u, xz, RANDS, MPFR_RNDZ);
inexa = mpfr_random_deviate_value (neg, n, u, xa, RANDS, MPFR_RNDA);
inext = mpfr_set (t, xn, MPFR_RNDN);
/* Check inexact values */
if ( !( inexn != 0 && inext == 0 &&
inexd < 0 && inexu > 0 &&
inexz * s < 0 && inexa * s > 0 ) )
{
printf ("n %d t %d d %d u %d z %d a %d s %d\n",
inexn, inext, inexd, inexu, inexz, inexa, s);
printf ("Error: random_deviate has wrong values for inexact.\n");
exit (1);
}
if (inexn < 0)
mpfr_nextabove (t);
else
mpfr_nextbelow (t);
/* Check that x{d,u,z,a} == xn is the inexact flags match, else
* x{d,u,z,a} == t */
if ( !( mpfr_equal_p(xd, SAME_SIGN(inexn, inexd) ? xn : t) &&
mpfr_equal_p(xu, SAME_SIGN(inexn, inexu) ? xn : t) &&
mpfr_equal_p(xz, SAME_SIGN(inexn, inexz) ? xn : t) &&
mpfr_equal_p(xa, SAME_SIGN(inexn, inexa) ? xn : t) ) )
{
printf ("n %d t %d d %d u %d z %d a %d s %d\n",
inexn, inext, inexd, inexu, inexz, inexa, s);
printf ("n %.4f t %.4f d %.4f u %.4f z %.4f a %.4f\n",
mpfr_get_d (xn, MPFR_RNDN), mpfr_get_d (t, MPFR_RNDN),
mpfr_get_d (xd, MPFR_RNDN), mpfr_get_d (xu, MPFR_RNDN),
mpfr_get_d (xz, MPFR_RNDN), mpfr_get_d (xa, MPFR_RNDN));
printf ("Error: random_deviate rounds inconsistently.\n");
exit (1);
}
}
mpfr_random_deviate_clear (u);
mpfr_clears (xn, xd, xu, xz, xa, t, (mpfr_ptr) 0);
}
/* Test mpfr_random_deviate_value. Check for the leading bit in the number in
* various positions. */
static void
test_value (long nbtests, mpfr_prec_t prec, mpfr_rnd_t rnd,
int verbose)
{
mpfr_t x;
mpfr_random_deviate_t u;
int inexact, exact;
int i, k, b, neg;
unsigned long e, f, n;
long count, sum;
mpfr_random_deviate_init (u);
mpfr_init2 (x, prec);
count = 0; sum = 0;
exact = 0;
for (k = 0; k < nbtests; ++k)
{
for (i = 0; i < 32; ++i)
{
b = gmp_urandomm_ui (RANDS, 32) + 1; /* bits to sample in integer */
n = gmp_urandomb_ui (RANDS, b);
neg = gmp_urandomb_ui (RANDS, 1);
inexact = mpfr_random_deviate_value (neg, n, u, x, RANDS, rnd);
if (!inexact)
exact = 1;
if (inexact > 0)
++count;
++sum;
}
for (i = 0; i < 32; ++i)
{
b = gmp_urandomm_ui (RANDS, W) + 1; /* bits to sample in fraction */
f = gmp_urandomb_ui (RANDS, b);
e = W * (gmp_urandomm_ui (RANDS, 3) + 1);
mpfr_random_deviate_ldexp (u, f, e);
neg = gmp_urandomb_ui (RANDS, 1);
inexact = mpfr_random_deviate_value (neg, 0, u, x, RANDS, rnd);
if (!inexact)
exact = 1;
if (inexact > 0)
++count;
++sum;
}
if (exact)
{
printf ("Error: random_deviate() returns a zero ternary value.\n");
exit (1);
}
mpfr_random_deviate_reset (u);
}
mpfr_random_deviate_clear (u);
mpfr_clear (x);
if (verbose)
{
printf ("Fraction of inexact > 0 = %.4f", count / (double) (sum));
if (rnd == MPFR_RNDD)
printf (" should be exactly 0\n");
else if (rnd == MPFR_RNDU)
printf (" should be exactly 1\n");
else
printf (" should be about 0.5\n");
}
}
int
main (int argc, char *argv[])
{
long nbtests;
int verbose;
long a;
tests_start_mpfr ();
verbose = 0;
nbtests = 10;
if (argc > 1)
{
a = atol (argv[1]);
verbose = 1;
if (a != 0)
nbtests = a;
}
test_compare (nbtests, verbose);
test_value_consistency (nbtests);
test_value_round (nbtests, 2);
test_value_round (nbtests, 64);
test_value (nbtests, 2, MPFR_RNDD, verbose);
test_value (nbtests, 5, MPFR_RNDU, verbose);
test_value (nbtests, 24, MPFR_RNDN, verbose);
test_value (nbtests, 53, MPFR_RNDZ, verbose);
test_value (nbtests, 64, MPFR_RNDA, verbose);
tests_end_mpfr ();
return 0;
}