1/* gen.c -- Generate pseudorandom numbers. 2 3Copyright 1999, 2000, 2002 Free Software Foundation, Inc. 4 5This file is part of the GNU MP Library test suite. 6 7The GNU MP Library test suite is free software; you can redistribute it 8and/or modify it under the terms of the GNU General Public License as 9published by the Free Software Foundation; either version 3 of the License, 10or (at your option) any later version. 11 12The GNU MP Library test suite is distributed in the hope that it will be 13useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 15Public License for more details. 16 17You should have received a copy of the GNU General Public License along with 18the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */ 19 20/* Examples: 21 22 $ gen 10 2310 integers 0 <= X < 2^32 generated by mpz_urandomb() 24 25 $ gen -f mpf_urandomb 10 2610 real numbers 0 <= X < 1 27 28 $ gen -z 127 10 2910 integers 0 <= X < 2^127 30 31 $ gen -f mpf_urandomb -x .9,1 10 3210 real numbers 0 <= X < .9 33 34 $ gen -s 1 10 3510 integers, sequence seeded with 1 36 37*/ 38 39#include <stdio.h> 40#include <stdlib.h> 41#include <unistd.h> 42#include <limits.h> 43#include <errno.h> 44#include <time.h> 45#include <string.h> 46 47#if !HAVE_DECL_OPTARG 48extern char *optarg; 49extern int optind, opterr; 50#endif 51 52#include "gmp-impl.h" 53 54int main (argc, argv) 55 int argc; 56 char *argv[]; 57{ 58 const char usage[] = 59 "usage: gen [-bhpq] [-a n] [-c a,c,m2exp] [-C a,c,m] [-f func] [-g alg] [-m n] [-s n] " \ 60 "[-x f,t] [-z n] [n]\n" \ 61 " n number of random numbers to generate\n" \ 62 " -a n ASCII output in radix n (default, with n=10)\n" \ 63 " -b binary output\n" \ 64 " -c a,c,m2exp use supplied LC scheme\n" \ 65 " -f func random function, one of\n" \ 66 " mpz_urandomb (default), mpz_urandomm, mpf_urandomb, rand, random\n" \ 67 " -g alg algorithm, one of mt (default), lc\n" \ 68 " -h print this text and exit\n" \ 69 " -m n maximum size of generated number plus 1 (0<= X < n) for mpz_urandomm\n" \ 70 " -p print used seed on stderr\n" \ 71 " -q quiet, no output\n" \ 72 " -s n initial seed (default: output from time(3))\n" \ 73 " -x f,t exclude all numbers f <= x <= t\n" \ 74 " -z n size in bits of generated numbers (0<= X <2^n) (default 32)\n" \ 75 ""; 76 77 unsigned long int f; 78 unsigned long int n = 0; 79 unsigned long int seed; 80 unsigned long int m2exp = 0; 81 unsigned int size = 32; 82 int seed_from_user = 0; 83 int ascout = 1, binout = 0, printseed = 0; 84 int output_radix = 10; 85 int lc_scheme_from_user = 0; 86 int quiet_flag = 0; 87 mpz_t z_seed; 88 mpz_t z1; 89 mpf_t f1; 90 gmp_randstate_t rstate; 91 int c, i; 92 double drand; 93 long lrand; 94 int do_exclude = 0; 95 mpf_t f_xf, f_xt; /* numbers to exclude from sequence */ 96 char *str_xf, *str_xt; /* numbers to exclude from sequence */ 97 char *str_a, *str_adder, *str_m; 98 mpz_t z_a, z_m, z_mmax; 99 unsigned long int ul_adder; 100 101 enum 102 { 103 RFUNC_mpz_urandomb = 0, 104 RFUNC_mpz_urandomm, 105 RFUNC_mpf_urandomb, 106 RFUNC_rand, 107 RFUNC_random, 108 } rfunc = RFUNC_mpz_urandomb; 109 char *rfunc_str[] = { "mpz_urandomb", "mpz_urandomm", "mpf_urandomb", 110 "rand", "random" }; 111 enum 112 { 113 RNG_MT = 0, 114 RNG_LC 115 }; 116 gmp_randalg_t ralg = RNG_MT; 117 /* Texts for the algorithms. The index of each must match the 118 corresponding algorithm in the enum above. */ 119 char *ralg_str[] = { "mt", "lc" }; 120 121 mpf_init (f_xf); 122 mpf_init (f_xt); 123 mpf_init (f1); 124 mpz_init (z1); 125 mpz_init (z_seed); 126 mpz_init_set_ui (z_mmax, 0); 127 128 129 while ((c = getopt (argc, argv, "a:bc:f:g:hm:n:pqs:z:x:")) != -1) 130 switch (c) 131 { 132 case 'a': 133 ascout = 1; 134 binout = 0; 135 output_radix = atoi (optarg); 136 break; 137 138 case 'b': 139 ascout = 0; 140 binout = 1; 141 break; 142 143 case 'c': /* User supplied LC scheme: a,c,m2exp */ 144 if (NULL == (str_a = strtok (optarg, ",")) 145 || NULL == (str_adder = strtok (NULL, ",")) 146 || NULL == (str_m = strtok (NULL, ","))) 147 { 148 fprintf (stderr, "gen: bad LC scheme parameters: %s\n", optarg); 149 exit (1); 150 } 151#ifdef HAVE_STRTOUL 152 ul_adder = strtoul (str_adder, NULL, 0); 153#elif HAVE_STRTOL 154 ul_adder = (unsigned long int) strtol (str_adder, NULL, 0); 155#else 156 ul_adder = (unsigned long int) atoi (str_adder); 157#endif 158 159 if (mpz_init_set_str (z_a, str_a, 0)) 160 { 161 fprintf (stderr, "gen: bad LC scheme parameter `a': %s\n", str_a); 162 exit (1); 163 } 164 if (ULONG_MAX == ul_adder) 165 { 166 fprintf (stderr, "gen: bad LC scheme parameter `c': %s\n", 167 str_adder); 168 exit (1); 169 } 170 m2exp = atol (str_m); 171 172 lc_scheme_from_user = 1; 173 break; 174 175 176 case 'f': 177 rfunc = -1; 178 for (f = 0; f < sizeof (rfunc_str) / sizeof (*rfunc_str); f++) 179 if (!strcmp (optarg, rfunc_str[f])) 180 { 181 rfunc = f; 182 break; 183 } 184 if (rfunc == -1) 185 { 186 fputs (usage, stderr); 187 exit (1); 188 } 189 break; 190 191 case 'g': /* algorithm */ 192 ralg = -1; 193 for (f = 0; f < sizeof (ralg_str) / sizeof (*ralg_str); f++) 194 if (!strcmp (optarg, ralg_str[f])) 195 { 196 ralg = f; 197 break; 198 } 199 if (ralg == -1) 200 { 201 fputs (usage, stderr); 202 exit (1); 203 } 204 break; 205 206 case 'm': /* max for mpz_urandomm() */ 207 if (mpz_set_str (z_mmax, optarg, 0)) 208 { 209 fprintf (stderr, "gen: bad max value: %s\n", optarg); 210 exit (1); 211 } 212 break; 213 214 case 'p': /* print seed on stderr */ 215 printseed = 1; 216 break; 217 218 case 'q': /* quiet */ 219 quiet_flag = 1; 220 break; 221 222 case 's': /* user provided seed */ 223 if (mpz_set_str (z_seed, optarg, 0)) 224 { 225 fprintf (stderr, "gen: bad seed argument %s\n", optarg); 226 exit (1); 227 } 228 seed_from_user = 1; 229 break; 230 231 case 'z': 232 size = atoi (optarg); 233 if (size < 1) 234 { 235 fprintf (stderr, "gen: bad size argument (-z %u)\n", size); 236 exit (1); 237 } 238 break; 239 240 case 'x': /* Exclude. from,to */ 241 str_xf = optarg; 242 str_xt = strchr (optarg, ','); 243 if (NULL == str_xt) 244 { 245 fprintf (stderr, "gen: bad exclusion parameters: %s\n", optarg); 246 exit (1); 247 } 248 *str_xt++ = '\0'; 249 do_exclude = 1; 250 break; 251 252 case 'h': 253 case '?': 254 default: 255 fputs (usage, stderr); 256 exit (1); 257 } 258 argc -= optind; 259 argv += optind; 260 261 if (! seed_from_user) 262 mpz_set_ui (z_seed, (unsigned long int) time (NULL)); 263 seed = mpz_get_ui (z_seed); 264 if (printseed) 265 { 266 fprintf (stderr, "gen: seed used: "); 267 mpz_out_str (stderr, output_radix, z_seed); 268 fprintf (stderr, "\n"); 269 } 270 271 mpf_set_prec (f1, size); 272 273 /* init random state and plant seed */ 274 switch (rfunc) 275 { 276 case RFUNC_mpf_urandomb: 277#if 0 278 /* Don't init a too small generator. */ 279 size = PREC (f1) * GMP_LIMB_BITS; 280 /* Fall through. */ 281#endif 282 case RFUNC_mpz_urandomb: 283 case RFUNC_mpz_urandomm: 284 switch (ralg) 285 { 286 case RNG_MT: 287 gmp_randinit_mt (rstate); 288 break; 289 290 case RNG_LC: 291 if (! lc_scheme_from_user) 292 gmp_randinit_lc_2exp_size (rstate, MIN (128, size)); 293 else 294 gmp_randinit_lc_2exp (rstate, z_a, ul_adder, m2exp); 295 break; 296 297 default: 298 fprintf (stderr, "gen: unsupported algorithm\n"); 299 exit (1); 300 } 301 302 gmp_randseed (rstate, z_seed); 303 break; 304 305 case RFUNC_rand: 306 srand (seed); 307 break; 308 309 case RFUNC_random: 310#ifdef __FreeBSD__ /* FIXME */ 311 if (seed_from_user) 312 srandom (seed); 313 else 314 srandomdev (); 315#else 316 fprintf (stderr, "gen: unsupported algorithm\n"); 317#endif 318 break; 319 320 default: 321 fprintf (stderr, "gen: random function not implemented\n"); 322 exit (1); 323 } 324 325 /* set up excludes */ 326 if (do_exclude) 327 switch (rfunc) 328 { 329 case RFUNC_mpf_urandomb: 330 331 if (mpf_set_str (f_xf, str_xf, 10) || 332 mpf_set_str (f_xt, str_xt, 10)) 333 { 334 fprintf (stderr, "gen: bad exclusion-from (\"%s\") " \ 335 "or exclusion-to (\"%s\") string. no exclusion done.\n", 336 str_xf, str_xt); 337 do_exclude = 0; 338 } 339 break; 340 341 default: 342 fprintf (stderr, "gen: exclusion not implemented for chosen " \ 343 "randomization function. all numbers included in sequence.\n"); 344 } 345 346 /* generate and print */ 347 if (argc > 0) 348 { 349#if HAVE_STRTOUL 350 n = strtoul (argv[0], (char **) NULL, 10); 351#elif HAVE_STRTOL 352 n = (unsigned long int) strtol (argv[0], (char **) NULL, 10); 353#else 354 n = (unsigned long int) atoi (argv[0]); 355#endif 356 } 357 358 for (f = 0; n == 0 || f < n; f++) 359 { 360 switch (rfunc) 361 { 362 case RFUNC_mpz_urandomb: 363 mpz_urandomb (z1, rstate, size); 364 if (quiet_flag) 365 break; 366 if (binout) 367 { 368 /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/ 369 fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n"); 370 exit (1); 371 } 372 else 373 { 374 mpz_out_str (stdout, output_radix, z1); 375 puts (""); 376 } 377 break; 378 379 case RFUNC_mpz_urandomm: 380 mpz_urandomm (z1, rstate, z_mmax); 381 if (quiet_flag) 382 break; 383 if (binout) 384 { 385 /*fwrite ((unsigned int *) z1->_mp_d, 4, 1, stdout);*/ 386 fprintf (stderr, "gen: binary output for mpz_urandom* is broken\n"); 387 exit (1); 388 } 389 else 390 { 391 mpz_out_str (stdout, output_radix, z1); 392 puts (""); 393 } 394 break; 395 396 case RFUNC_mpf_urandomb: 397 mpf_urandomb (f1, rstate, size); 398 if (do_exclude) 399 if (mpf_cmp (f1, f_xf) >= 0 && mpf_cmp (f1, f_xt) <= 0) 400 break; 401 if (quiet_flag) 402 break; 403 if (binout) 404 { 405 fprintf (stderr, "gen: binary output for floating point numbers "\ 406 "not implemented\n"); 407 exit (1); 408 } 409 else 410 { 411 mpf_out_str (stdout, output_radix, 0, f1); 412 puts (""); 413 } 414 break; 415 416 case RFUNC_rand: 417 i = rand (); 418#ifdef FLOAT_OUTPUT 419 if (i) 420 drand = (double) i / (double) RAND_MAX; 421 else 422 drand = 0.0; 423 if (quiet_flag) 424 break; 425 if (binout) 426 fwrite (&drand, sizeof (drand), 1, stdout); 427 else 428 printf ("%e\n", drand); 429#else 430 if (quiet_flag) 431 break; 432 if (binout) 433 fwrite (&i, sizeof (i), 1, stdout); 434 else 435 printf ("%d\n", i); 436#endif 437 break; 438 439 case RFUNC_random: 440 lrand = random (); 441 if (lrand) 442 drand = (double) lrand / (double) 0x7fffffff; 443 else 444 drand = 0; 445 if (quiet_flag) 446 break; 447 if (binout) 448 fwrite (&drand, sizeof (drand), 1, stdout); 449 else 450 printf ("%e\n", drand); 451 break; 452 453 default: 454 fprintf (stderr, "gen: random function not implemented\n"); 455 exit (1); 456 } 457 458 } 459 460 /* clean up */ 461 switch (rfunc) 462 { 463 case RFUNC_mpz_urandomb: 464 case RFUNC_mpf_urandomb: 465 gmp_randclear (rstate); 466 break; 467 default: 468 break; 469 } 470 mpf_clear (f1); 471 mpf_clear (f_xf); 472 mpf_clear (f_xt); 473 mpz_clear (z1); 474 mpz_clear (z_seed); 475 476 return 0; 477} 478 479static void *debug_dummyz = mpz_dump; 480static void *debug_dummyf = mpf_dump; 481