1/* random.c -- Handle seed for random numbers. 2 3// Copyright (C) 2008, 2009, 2010, 2011, 2012 INRIA 4 5This file is part of GNU MPC. 6 7GNU MPC is free software; you can redistribute it and/or modify it under 8the terms of the GNU Lesser General Public License as published by the 9Free Software Foundation; either version 3 of the License, or (at your 10option) any later version. 11 12GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY 13WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 14FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for 15more details. 16 17You should have received a copy of the GNU Lesser General Public License 18along with this program. If not, see http://www.gnu.org/licenses/ . 19*/ 20 21/* Put test_start at the beginning of your test function and 22 test_end at the end. 23 These are an adaptation of those of MPFR. */ 24 25#include "config.h" 26#include <stdlib.h> 27#include "mpc-tests.h" 28 29 30#ifdef TIME_WITH_SYS_TIME 31# include <sys/time.h> 32# include <time.h> 33#else 34# ifdef HAVE_SYS_TIME_H 35# include <sys/time.h> 36# else 37# include <time.h> 38# endif 39#endif 40 41gmp_randstate_t rands; 42static char rands_initialized; 43 44void 45test_start (void) 46{ 47 char *environment_seed; 48 unsigned long seed; 49 50 if (rands_initialized) 51 { 52 fprintf (stderr, 53 "Put test_start at the beginning of your test function.\n"); 54 exit (1); 55 } 56 57 gmp_randinit_default (rands); 58 rands_initialized = 1; 59 60 environment_seed = getenv ("GMP_CHECK_RANDOMIZE"); 61 if (environment_seed == NULL) 62 gmp_randseed_ui (rands, 0xfac11e); 63 else 64 { 65 seed = (unsigned long int) atoi (environment_seed); 66 if (seed == 0 || seed == 1) 67 { 68#if defined HAVE_GETTIMEOFDAY 69 struct timeval tv; 70 gettimeofday (&tv, NULL); 71 seed = (unsigned long int) (tv.tv_sec + tv.tv_usec); 72#else 73 time_t tv; 74 time (&tv); 75 seed = (unsigned long int) tv; 76#endif 77 gmp_randseed_ui (rands, seed); 78 printf ("Seed GMP_CHECK_RANDOMIZE=%lu " 79 "(include this in bug reports)\n", seed); 80 } 81 else 82 { 83 printf ("Re-seeding with GMP_CHECK_RANDOMIZE=%lu\n", seed); 84 gmp_randseed_ui (rands, seed); 85 } 86 } 87 88 /* some tests assume a given exponent range for MPFR, thus since the 89 default exponent range for MPFR is not specified, we hard-code it */ 90 mpfr_set_emax (1073741821); 91 mpfr_set_emin (-1073741821); 92} 93 94void 95test_end (void) 96{ 97 if (rands_initialized) 98 { 99 rands_initialized = 0; 100 gmp_randclear (rands); 101 } 102 mpfr_free_cache (); 103} 104 105/* Set z to a non zero value random value with absolute values of Re(z) and 106 Im(z) either zero (but not both in the same time) or otherwise greater than 107 or equal to 2^{emin-1} and less than 2^emax. 108 Each part is negative with probability equal to NEGATIVE_PROBABILITY / 256. 109 The result has one zero part (but never the two of them) with probability 110 equal to ZERO_PROBABILITY / 256. 111*/ 112void 113test_default_random (mpc_ptr z, mpfr_exp_t emin, mpfr_exp_t emax, 114 unsigned int negative_probability, 115 unsigned int zero_probability) 116{ 117 const unsigned long range = (unsigned long int) (emax - emin) + 1; 118 unsigned long r; 119 120 if (!rands_initialized) 121 { 122 fprintf (stderr, 123 "Put test_start at the beginning of your test function.\n"); 124 exit (1); 125 } 126 127 do 128 { 129 mpc_urandom (z, rands); 130 } while (mpfr_zero_p (mpc_realref (z)) || mpfr_zero_p (mpc_imagref (z))); 131 132 if (zero_probability > 256) 133 zero_probability = 256; 134 r = gmp_urandomb_ui (rands, 19); 135 if ((r & 0x1FF) < zero_probability 136 || ((r >> 9) & 0x1FF) < zero_probability) 137 { 138 int zero_re_p = (r & 0x1FF) < zero_probability; 139 int zero_im_p = ((r >> 9) & 0x1FF) < zero_probability; 140 141 if (zero_re_p && zero_im_p) 142 { 143 /* we just want one zero part. */ 144 zero_re_p = (r >> 18) & 1; 145 zero_im_p = !zero_re_p; 146 } 147 if (zero_re_p) 148 mpfr_set_ui (mpc_realref (z), 0, MPFR_RNDN); 149 if (zero_im_p) 150 mpfr_set_ui (mpc_imagref (z), 0, MPFR_RNDN); 151 } 152 if (!mpfr_zero_p (mpc_realref (z))) 153 mpfr_set_exp (mpc_realref (z), (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin); 154 155 if (!mpfr_zero_p (mpc_imagref (z))) 156 mpfr_set_exp (mpc_imagref (z), (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin); 157 158 if (negative_probability > 256) 159 negative_probability = 256; 160 r = gmp_urandomb_ui (rands, 16); 161 if ((r & 0xFF) < negative_probability) 162 mpfr_neg (mpc_realref (z), mpc_realref (z), MPFR_RNDN); 163 if (((r>>8) & 0xFF) < negative_probability) 164 mpfr_neg (mpc_imagref (z), mpc_imagref (z), MPFR_RNDN); 165} 166 167/* Set n to a non zero value random value with absolute values less than 168 2^emax. 169 170 n is negative with probability equal to NEGATIVE_PROBABILITY / 256. 171*/ 172void test_random_si (long int *n, unsigned long emax, 173 unsigned int negative_probability) 174{ 175 unsigned long r; 176 177 if (!rands_initialized) 178 { 179 fprintf (stderr, 180 "Put test_start at the beginning of your test function.\n"); 181 exit (1); 182 } 183 184 do 185 { 186 *n = gmp_urandomb_ui (rands, emax); 187 } while (*n == 0); 188 189 if (negative_probability > 256) 190 negative_probability = 256; 191 r = gmp_urandomb_ui (rands, 8); 192 if ((r & 0xFF) < negative_probability) 193 *n = -(*n); 194} 195 196/* Set x to a non zero value random value with absolute values greater than 197 or equal to 2^{emin-1} and less than 2^emax. 198 199 x is negative with probability equal to NEGATIVE_PROBABILITY / 256. 200*/ 201void 202test_random_mpfr (mpfr_ptr x, mpfr_exp_t emin, mpfr_exp_t emax, 203 unsigned int negative_probability) 204{ 205 const unsigned long range = (unsigned long int) (emax - emin) + 1; 206 unsigned long r; 207 208 if (!rands_initialized) 209 { 210 fprintf (stderr, 211 "Put test_start at the beginning of your test function.\n"); 212 exit (1); 213 } 214 215 do 216 { 217 mpfr_urandom (x, rands, MPFR_RNDN); 218 } while (mpfr_zero_p (x)); 219 220 mpfr_set_exp (x, (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin); 221 if (negative_probability > 256) 222 negative_probability = 256; 223 r = gmp_urandomb_ui (rands, 8); 224 if ((r & 0xFF) < negative_probability) 225 mpfr_neg (x, x, MPFR_RNDN); 226} 227 228/* Set x to a non zero value random value. 229 x is negative with probability equal to NEGATIVE_PROBABILITY / 256. 230*/ 231void 232test_random_d (double *x, unsigned int negative_probability) 233{ 234 MPFR_DECL_INIT (mpfr_x, 53); 235 test_random_mpfr (mpfr_x, -1022, 1022, negative_probability); 236 *x = mpfr_get_d (mpfr_x, MPFR_RNDN); 237} 238 239/* Set z to a non zero value random value with absolute values of Re(z) and 240 Im(z) greater than or equal to 2^{emin-1} and less than 2^emax. 241 242 Each part is negative with probability equal to NEGATIVE_PROBABILITY / 256. 243*/ 244void 245test_random_mpc (mpc_ptr z, mpfr_exp_t emin, mpfr_exp_t emax, 246 unsigned int negative_probability) 247{ 248 const unsigned long range = (unsigned long int) (emax - emin) + 1; 249 unsigned long r; 250 251 if (!rands_initialized) 252 { 253 fprintf (stderr, 254 "Put test_start at the beginning of your test function.\n"); 255 exit (1); 256 } 257 258 do 259 { 260 mpc_urandom (z, rands); 261 } while (mpfr_zero_p (mpc_realref (z)) || mpfr_zero_p (mpc_imagref (z))); 262 263 mpfr_set_exp (mpc_realref (z), 264 (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin); 265 266 mpfr_set_exp (mpc_imagref (z), 267 (mpfr_exp_t) gmp_urandomm_ui (rands, range) + emin); 268 269 if (negative_probability > 256) 270 negative_probability = 256; 271 r = gmp_urandomb_ui (rands, 16); 272 if ((r & 0xFF) < negative_probability) 273 mpfr_neg (mpc_realref (z), mpc_realref (z), MPFR_RNDN); 274 if (((r>>8) & 0xFF) < negative_probability) 275 mpfr_neg (mpc_imagref (z), mpc_imagref (z), MPFR_RNDN); 276} 277