/* random.c -- Handle seed for random numbers. // Copyright (C) 2008, 2009, 2010, 2011 INRIA This file is part of GNU MPC. GNU MPC 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. GNU MPC 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 this program. If not, see http://www.gnu.org/licenses/ . */ /* Put test_start at the beginning of your test function and test_end at the end. These are an adaptation of those of MPFR. */ #include "config.h" #include #include "mpc-tests.h" #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif gmp_randstate_t rands; static char rands_initialized; void test_start (void) { char *environment_seed; unsigned long seed; if (rands_initialized) { fprintf (stderr, "Put test_start at the beginning of your test function.\n"); exit (1); } gmp_randinit_default (rands); rands_initialized = 1; environment_seed = getenv ("GMP_CHECK_RANDOMIZE"); if (environment_seed == NULL) gmp_randseed_ui (rands, 0xfac11e); else { seed = (unsigned long int) atoi (environment_seed); if (seed == 0 || seed == 1) { #if defined HAVE_GETTIMEOFDAY struct timeval tv; gettimeofday (&tv, NULL); seed = (unsigned long int) (tv.tv_sec + tv.tv_usec); #else time_t tv; time (&tv); seed = (unsigned long int) tv; #endif gmp_randseed_ui (rands, seed); printf ("Seed GMP_CHECK_RANDOMIZE=%lu " "(include this in bug reports)\n", seed); } else { printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%lu\n", seed); gmp_randseed_ui (rands, seed); } } } void test_end (void) { if (rands_initialized) { rands_initialized = 0; gmp_randclear (rands); } mpfr_free_cache (); } /* Set z to a non zero value random value with absolute values of Re(z) and Im(z) either zero (but not both in the same time) or otherwise greater than or equal to 2^{emin-1} and less than 2^emax. Each part is negative with probability equal to NEGATIVE_PROBABILITY / 256. The result has one zero part (but never the two of them) with probability equal to ZERO_PROBABILITY / 256. */ void test_default_random (mpc_ptr z, mpfr_exp_t emin, mpfr_exp_t emax, unsigned int negative_probability, unsigned int zero_probability) { const unsigned long range = (unsigned long int) (emax - emin) + 1; unsigned long r; if (!rands_initialized) { fprintf (stderr, "Put test_start at the beginning of your test function.\n"); exit (1); } do { mpc_urandom (z, rands); } while (mpfr_zero_p (mpc_realref (z)) || mpfr_zero_p (mpc_imagref (z))); if (zero_probability > 256) zero_probability = 256; r = gmp_urandomb_ui (rands, 19); if ((r & 0x1FF) < zero_probability || ((r >> 9) & 0x1FF) < zero_probability) { int zero_re_p = (r & 0x1FF) < zero_probability; int zero_im_p = ((r >> 9) & 0x1FF) < zero_probability; if (zero_re_p && zero_im_p) { /* we just want one zero part. */ zero_re_p = (r >> 18) & 1; zero_im_p = !zero_re_p; } if (zero_re_p) mpfr_set_ui (mpc_realref (z), 0, GMP_RNDN); if (zero_im_p) mpfr_set_ui (mpc_imagref (z), 0, GMP_RNDN); } if (!mpfr_zero_p (mpc_realref (z))) mpfr_set_exp (mpc_realref (z), (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin); if (!mpfr_zero_p (mpc_imagref (z))) mpfr_set_exp (mpc_imagref (z), (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin); if (negative_probability > 256) negative_probability = 256; r = gmp_urandomb_ui (rands, 16); if ((r & 0xFF) < negative_probability) mpfr_neg (mpc_realref (z), mpc_realref (z), GMP_RNDN); if (((r>>8) & 0xFF) < negative_probability) mpfr_neg (mpc_imagref (z), mpc_imagref (z), GMP_RNDN); }